Skip to content

Instantly share code, notes, and snippets.

@tomoasleep
Last active September 2, 2019 02:19
Show Gist options
  • Save tomoasleep/4e86f11750ec71f0de1c946797956d49 to your computer and use it in GitHub Desktop.
Save tomoasleep/4e86f11750ec71f0de1c946797956d49 to your computer and use it in GitHub Desktop.
https://github.com/gjtorikian/commonmarker 使って Markdown のチェックボックス一覧取得したり、チェックボックス toggle したりできるやつ
class TaskList
attr_reader :markdown
# @param markdown [String]
def initialize(markdown)
@markdown = markdown
end
# @return [CommonMarker::Node]
def document
@document ||= CommonMarker.render_doc(markdown, :DEFAULT, [:tasklist])
end
# @return [Array<Checkbox>]
def checkboxes
@checkboxes ||= document.walk.select { |node| node.type_string == 'tasklist' }.map { |node| Checkbox.new(node) }
end
# @return [String]
def to_plaintext
checkboxes.select(&:modified?).reduce(markdown) do |text, checkbox|
start_pos = index_from(line: checkbox.sourcepos[:start_line], column: checkbox.sourcepos[:start_column])
checkbox_text = checkbox.to_plaintext
after_start_pos = start_pos + checkbox_text.length
text.slice(0...start_pos) + checkbox_text + (text.slice(after_start_pos..-1) || '')
end
end
private
# @param line [Integer] 1-indexed line number.
# @param column [Integer] 1-indexed column number.
# @return [Integer] the index of the head of the given point.
def index_from(line:, column:)
lines = @markdown.lines
above_lines = lines.slice(0, line - 1)
current_line = lines[line - 1]
ahead_source = above_lines.join('') + current_line.slice(0, column - 1)
ahead_source.length
end
class Checkbox
# @param node [CommonMarker::Node]
def initialize(node)
@node = node
@check_state = nil
end
def checked?
@check_state.nil? ? literally_checked? : @check_state
end
def check
@check_state = true
end
def uncheck
@check_state = false
end
def sourcepos
@node.sourcepos
end
def modified?
!@check_state.nil? && (checked? != literally_checked?)
end
def to_plaintext
if @check_state.nil?
@node.to_plaintext
else
@node.to_plaintext.sub(/\[( |x)\]/, checked? ? '[x]' : '[ ]')
end
end
def content
@node.to_a.first.to_plaintext
end
def literally_checked?
@node.tasklist_state == 'checked'
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment