Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 118 additions & 49 deletions plugins/markdown-actions/markdown-actions.vala
Original file line number Diff line number Diff line change
Expand Up @@ -94,69 +94,86 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services

if (keyval == Gdk.Key.Return) {
char ul_marker;
int ol_number = 1;
int ol_number;
string prefix;
string item_text;
var line = get_current_line ();
if (parse_unordered_list_item (line, out ul_marker)) {
if (line.length <= 3) { // empty item
delete_empty_item ();

if (parse_ordered_list_item (line, out ol_number, out item_text, out prefix, null)) {
if (item_text.strip () == "") {
delete_empty_item (prefix);
} else {
string to_insert = "\n%c ".printf (ul_marker);
string to_insert = "\n%s%d. ".printf (prefix, ++ol_number);
current_source.buffer.insert_at_cursor (to_insert, to_insert.length);
// Check following lines to see if renumbering required
fix_ordered_list_numbering (prefix.length, ol_number);
}
return true;
} else if (parse_ordered_list_item (line, ref ol_number, out item_text)) {
if (item_text.length == 0) {
delete_empty_item ();
} else {
string to_insert = "\n%d. ".printf (ol_number + 1);
} else if (parse_unordered_list_item (line, out ul_marker, out item_text, out prefix)) {
if (item_text.strip () == "") {
delete_empty_item (prefix);
} else { // ul_marker is not null here
string to_insert = "\n%s%c ".printf (prefix, ul_marker);
current_source.buffer.insert_at_cursor (to_insert, to_insert.length);
fix_ordered_list_numbering ();
}

return true;
}
}

return false;
}

private void delete_empty_item () {
private void delete_empty_item (string prefix = "") {
Gtk.TextIter start, end;
var current_buffer = current_source.buffer;
current_buffer.get_iter_at_offset (out start, current_buffer.cursor_position);
start.backward_chars (start.get_line_offset ());
end = start;
end.forward_to_line_end ();
current_buffer.delete (ref start, ref end);
current_buffer.insert_at_cursor ("\n", 1);
var _prefix = prefix;
if (prefix.strip () == "") {
_prefix = "";
}
current_buffer.insert_at_cursor ("%s".printf (_prefix), _prefix.length);
current_buffer.get_iter_at_offset (out start, current_buffer.cursor_position);
}

private void fix_ordered_list_numbering () {
// Starting on the line where a numbered list item was inserted, check if renumbering required
private void fix_ordered_list_numbering (int indent_spaces, int inserted_number) {
Gtk.TextIter next;
var count = 1;
var item_text = "";
var current_buffer = current_source.buffer;

current_buffer.get_iter_at_offset (out next, current_buffer.cursor_position);
var line = get_current_line (next).strip ();
// Get list item number from current line
parse_ordered_list_item (line, ref count, out item_text);
while (
next.forward_line () &&
parse_ordered_list_item (get_current_line (next).strip (), ref count, out item_text)
int point_offset = 0, count = inserted_number, next_count = 0;
string item_text = "", next_prefix = "";
// Search for ordered list lines at the same level until level falls below or end of doc
while (next.forward_line () &&
parse_ordered_list_item (
get_current_line (next),
out next_count,
out item_text,
out next_prefix,
out point_offset
) &&
next_prefix.length >= indent_spaces
) {
count++;
var next_mark = current_buffer.create_mark (null, next, true);
var point_offset = line.index_of_char ('.');
var start = next;
var end = start;
end.forward_chars (point_offset);

current_buffer.delete (ref start, ref end);
current_buffer.get_iter_at_mark (out next, next_mark);

var to_insert = "%d".printf (count);
current_buffer.insert (ref next, to_insert, to_insert.length);
// Only update lines at same indent within same block
if (next_prefix.length == indent_spaces) {
count++;
next.forward_chars (indent_spaces);
var next_mark = current_buffer.create_mark (null, next, true);
var start = next;
var end = start;
end.forward_chars (point_offset - indent_spaces);

current_buffer.delete (ref start, ref end);
current_buffer.get_iter_at_mark (out next, next_mark);

var to_insert = "%d".printf (count);
current_buffer.insert (ref next, to_insert, to_insert.length);
}
}
}

Expand All @@ -172,32 +189,84 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services
end = start;
end.forward_to_line_end ();

return current_buffer.get_text (start, end, false);
var cl = current_buffer.get_text (start, end, false);
return cl;
}

private bool parse_ordered_list_item (string line, ref int current_number, out string item_text) {
private bool parse_ordered_list_item (
string line,
out int current_number,
out string item_text,
out string prefix,
out int first_point_pos
) {
item_text = "";
int first_point_character = line.index_of_char ('.');
if (first_point_character < 0) {
return false;
}
prefix = "";
current_number = -1;
// Github does not automatically handle sublists in numbered lists so neither do we for now
// We assume the first number point is the only one.
first_point_pos = line.index_of_char ('.'); //TODO Handle ")" Ignored escaped?

item_text = line.substring (first_point_pos + 1).strip ();

item_text = line.substring (first_point_character + 1).strip ();
var line_start = line.substring (0, first_point_pos);
line_start = line_start.replace ("-", " ").replace ("*", " ");
prefix = line.substring (0, line_start.last_index_of_char (' ') + 1);

var line_start = line.substring (0, first_point_character);
if (!int.try_parse (line_start, out current_number)) {
return false;
}
return true;

return current_number >= 1;
}

private bool parse_unordered_list_item (string line, out char ul_marker) {
if ((line[0] == '*' || line[0] == '-') && line[1] == ' ') {
ul_marker = line[0];
return true;
private bool parse_unordered_list_item (
string line,
out char ul_marker,
out string item_text,
out string prefix
) {
prefix = "";
item_text = "";
ul_marker = ' ';

// Scan line for last unordered list marker
unichar uc = 0;
int index = 0;
uint spaces = 0;
char? last_marker = null;
while (line.get_next_char (ref index, out uc)) {
string buf = " ";
var i = uc.to_utf8 (buf);
if (i != 1) {
break;
}

var c = buf[0];
if (c.isspace ()) {
spaces++;
// Only allow one space between or after markers but any number before the first
if (last_marker != null && spaces > 1) {
break;
}
} else if (c == '-' || c == '*') {
spaces = 0;
last_marker = c;
} else { // text item starts here
break;
}
}
ul_marker = '\0';
return false;

if (last_marker == null) {
return false;
}

ul_marker = last_marker;
item_text = line.substring (index - 1);
// The item text might contain marker characters so take care to ignore those
prefix = line.substring (0, index - 1);
prefix = prefix.substring (0, prefix.last_index_of_char (ul_marker));
return true;
}

private void insert_link () {
Expand Down