Last active
September 2, 2019 02:19
-
-
Save tomoasleep/4e86f11750ec71f0de1c946797956d49 to your computer and use it in GitHub Desktop.
https://github.com/gjtorikian/commonmarker 使って Markdown のチェックボックス一覧取得したり、チェックボックス toggle したりできるやつ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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