Skip to content

Commit ffd32f0

Browse files
committed
Added underscored text styles
1 parent 324690d commit ffd32f0

File tree

5 files changed

+160
-120
lines changed

5 files changed

+160
-120
lines changed

after/ftplugin/markdown.vim

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,24 @@ var code_regex = '\v(\\|`)@<!``@!'
1818
# var italic_regex = '\v(\\|\*)@<!\*\*@!'
1919
# The following picks standalone * and the last * of \**
2020
# It excludes escaped * (i.e. \*\*\*, and sequences like ****)
21-
var italic_regex = '\v((\\|\*)@<!|(\\\*)@<=)\*\*@!'
21+
var italic_regex = '\v((\\|\*)@<!|(\\\*))@<=\*\*@!'
22+
var italic_regex_u = '\v((\\|_)@<!|(\\_))@<=_(_)@!'
2223
var bold_regex = '\v(\\|\*)@<!\*\*\*@!'
24+
var bold_regex_u = '\v(\\|_)@<!___@!'
2325
var strikethrough_regex = '\v(\\|\~)@<!\~\~\~@!'
2426

2527
export var text_style_dict = {'`': code_regex,
2628
'*': italic_regex,
2729
'**': bold_regex,
30+
'_': italic_regex_u,
31+
'__': bold_regex_u,
2832
'~~': strikethrough_regex}
2933

3034
export var code_dict = {'`': code_regex}
3135
export var italic_dict = {'*': italic_regex}
3236
export var bold_dict = {'**': bold_regex}
37+
export var italic_dict_u = {'_': italic_regex_u}
38+
export var bold_dict_u = {'__': bold_regex_u}
3339
export var strikethrough_dict = {'~~': strikethrough_regex}
3440

3541
if exists('g:markdown_extras_config') != 0

lib/utils.vim

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,6 @@ export def ZipLists(l1: list<any>, l2: list<any>): list<list<any>>
2727
return map(range(min_len), $'[{l1}[v:val], {l2}[v:val]]')
2828
enddef
2929

30-
export def RegexList2RegexOR(regex_list: list<string>,
31-
very_magic: bool = false): string
32-
# Convert a list of regex into an atom where each regex is separated by a OR
33-
# condition
34-
35-
var result = ''
36-
if very_magic
37-
result = regex_list->map((_, val) => substitute(val, '^\(\\v\)', '', ''))
38-
->join('|')->printf('\v(%s)')
39-
else
40-
result = regex_list->join('\|')->printf('\(%s\)')
41-
endif
42-
return result
43-
enddef
44-
4530
export def GetTextObject(textobject: string): dict<any>
4631
# You pass a text object like 'iw' and it returns the text
4732
# associated to it along with the start and end positions
@@ -113,7 +98,6 @@ export def RemoveSurrounding(
11398
# Remove right delimiter
11499
var lB = interval[1][1]
115100
var cB = interval[1][2]
116-
# echom "cB: " .. cB
117101
# The value of cB may no longer be valid since we shortened the line
118102
if lA == lB
119103
cB = cB - len(keys(open_delimiter_dict)[0])
@@ -123,7 +107,6 @@ export def RemoveSurrounding(
123107
strcharpart(getline(lB), 0, cB)
124108
.. strcharpart(getline(lB), cB + len(keys(close_delimiter_dict)[0]))
125109
setline(lB, newline)
126-
# echom "lB: " .. newline
127110
endif
128111
enddef
129112

@@ -146,7 +129,6 @@ export def SurroundSimple(open_delimiter: string,
146129
if !empty(text_object)
147130
# GetTextObject is called for setting '[ and '] marks through a yank.
148131
var text_object_dict = GetTextObject(text_object)
149-
echom text_object
150132
A = text_object_dict.start
151133
B = text_object_dict.end
152134
endif
@@ -204,7 +186,6 @@ export def SurroundSmart(open_delimiter: string,
204186
if !empty(text_object)
205187
# GetTextObject is called for setting '[ and '] marks through a yank.
206188
var text_object_dict = GetTextObject(text_object)
207-
echom text_object
208189
A = text_object_dict.start
209190
B = text_object_dict.end
210191
endif
@@ -323,32 +304,43 @@ export def SurroundSmart(open_delimiter: string,
323304
# Next, we have to adjust the text between A and B, by removing all the
324305
# possible delimiters left between them.
325306

326-
var all_delimiters_regex =
327-
RegexList2RegexOR(values(open_delimiters_dict), true)
328-
329307
# If on the same line
330308
if lA == lB
331309
# Overwrite everything that is in the middle
332310
var A_to_B = ''
333311

334312
A_to_B = strcharpart(getline(lA), cA - 1, cB - cA + 1)
335-
->substitute(all_delimiters_regex, '', 'g')
313+
for regex in values(open_delimiters_dict)
314+
A_to_B = A_to_B->substitute(regex, '', 'g')
315+
endfor
336316

337317
setline(lA, toA .. A_to_B .. fromB)
338318

339319
else
340-
var lineA = toA .. strcharpart(getline(lA), cA - 1)
341-
->substitute(all_delimiters_regex, '', 'g')
342-
echom "lineA: " .. lineA
320+
# Set line A
321+
var afterA = strcharpart(getline(lA), cA - 1)
322+
for regex in values(open_delimiters_dict)
323+
afterA = afterA->substitute(regex, '', 'g')
324+
endfor
325+
var lineA = toA .. afterA
343326
setline(lA, lineA)
344-
var lineB = strcharpart(getline(lB), 0, cB - 1)
345-
->substitute(all_delimiters_regex, '', 'g') .. fromB
346-
echom "lineB: " .. lineB
327+
328+
# Set line B
329+
var beforeB = strcharpart(getline(lB), 0, cB - 1)
330+
for regex in values(open_delimiters_dict)
331+
beforeB = beforeB->substitute(regex, '', 'g')
332+
endfor
333+
var lineB = beforeB .. fromB
347334
setline(lB, lineB)
348-
var l = 1
335+
349336
# Fix intermediate lines
337+
var l = 1
350338
while lA + l < lB
351-
setline(lA + l, getline(lA + l)->substitute(all_delimiters_regex, '', 'g') )
339+
var middleline = getline(lA + l)
340+
for regex in values(open_delimiters_dict)
341+
middleline = middleline-> substitute(regex, '', 'g')
342+
endfor
343+
setline(lA + l, middleline)
352344
l += 1
353345
endwhile
354346
endif
@@ -579,10 +571,6 @@ export def IsInRange(
579571
setcharpos("'a", range[0])
580572
setcharpos("'b", range[1])
581573
if IsBetweenMarks("'a", "'b")
582-
# echom "cur_pos: " .. string(getcharpos('.'))
583-
# echom "range[0]: " .. string(range[0])
584-
# echom "range[1]: " .. string(range[1])
585-
echom IsBetweenMarks("'a", "'b")
586574
interval = [range[0], range[1]]
587575
break
588576
endif

test/runner.vim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ def RunTests(test_file: string)
2424
->sort()
2525

2626
# Check is user defined some function name erroneously
27-
var wrong_test_functions = copy(all_functions)->filter('v:val !~ "Test_"')
27+
var wrong_test_functions = copy(all_functions)->filter('v:val !~ "^Test_"')
2828
echom "wrong_functions: " .. string(wrong_test_functions)
2929
if !empty(wrong_test_functions)
3030
writefile([$'WARNING: The following tests are skipped: {wrong_test_functions}'], 'results.txt', 'a')
3131
writefile([''], 'results.txt', 'a')
3232
endif
3333

3434
# Pick the good functions
35-
var test_functions = copy(all_functions)->filter('v:val =~ "Test_"')
35+
var test_functions = copy(all_functions)->filter('v:val =~ "^Test_"')
3636
echom "test_functions: " .. string(test_functions)
3737
if test_functions->empty()
3838
# No tests are found

test/test_regex.vim

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ vim9script noclear
22

33
import "../after/ftplugin/markdown.vim"
44

5+
var code_regex = markdown.code_dict['`']
56
var italic_regex = markdown.italic_dict['*']
67
var bold_regex = markdown.bold_dict['**']
7-
var code_regex = markdown.code_dict['`']
8+
var italic_regex_u = markdown.italic_dict_u['_']
9+
var bold_regex_u = markdown.bold_dict_u['__']
810
var strikethrough_regex = markdown.strikethrough_dict['~~']
911

1012
var src_name = 'testfile.md'
@@ -27,6 +29,22 @@ def Generate_markdown_testfile()
2729
Quis autem ~vel eum iure reprehenderit qui in ea voluptate velit esse
2830
quam nihil molestiae consequatur,~ vel `illum qui \~ dolorem eum` fugiat quo
2931
voluptas nulla \` pariatur``?
32+
33+
At vero eos et _accusamus et iusto odio dignissimos ducimus qui blanditiis
34+
praesentium voluptatum deleniti_ atque corrupti \_quos dolores et quas molestias
35+
excepturi sint occaecati _cupiditate_ non \_provident, similique sunt in culpa qui
36+
officia deserunt \__mollitia animi_, id est laborum et dolorum fuga. Et harum
37+
quidem rerum facilis est et expedita distinctio.
38+
39+
Nam libero tempore, __cum soluta nobis est eligendi optio cumque nihil
40+
impedit quo minus id quod maxime placeat facere possimus, omnis
41+
voluptas assumenda est__, omnis dolor repellendus. Temporibus autem
42+
quibusdam et aut officiis debitis aut rerum necessitatibus saepe
43+
eveniet ut et voluptates repudiandae sint et molestiae non recusandae.
44+
45+
Itaque earum rerum hic tenetur a sapiente delectus, ut aut
46+
reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus
47+
asperiores repellat
3048
END
3149
writefile(lines, src_name)
3250
enddef
@@ -37,6 +55,7 @@ enddef
3755

3856
# Tests start here
3957
def g:Test_regex()
58+
vnew
4059
Generate_markdown_testfile()
4160

4261
exe $"edit {src_name}"
@@ -87,6 +106,29 @@ def g:Test_regex()
87106
endwhile
88107
assert_equal(expected_pos, actual_pos)
89108

109+
# italic underscore
110+
expected_pos = [[18, 16], [19, 32], [20, 26],
111+
[20, 37], [21, 20], [21, 35], [0, 0]]
112+
actual_pos = []
113+
tmp = []
114+
cursor(1, 1)
115+
while tmp != [0, 0]
116+
tmp = searchpos(italic_regex_u, 'W')
117+
add(actual_pos, tmp)
118+
endwhile
119+
assert_equal(expected_pos, actual_pos)
120+
121+
# bold underscore
122+
expected_pos = [[24, 21], [26, 23], [0, 0]]
123+
actual_pos = []
124+
tmp = []
125+
cursor(1, 1)
126+
while tmp != [0, 0]
127+
tmp = searchpos(bold_regex_u, 'W')
128+
add(actual_pos, tmp)
129+
endwhile
130+
assert_equal(expected_pos, actual_pos)
131+
90132
# redraw!
91133
# sleep 3
92134
:%bw!

0 commit comments

Comments
 (0)