howl.modes.DefaultMode
local buffer, mode, lines, indentation
editor = Editor Buffer {}
cursor = editor.cursor
selection = editor.selection
indent = ->
selection\select_all!
mode\indent editor
before_each ->
buffer = Buffer {}
mode = DefaultMode!
indentation = {}
mode.indentation = indentation
buffer.mode = mode
buffer.config.indent = 2
lines = buffer.lines
editor.buffer = buffer
.indent()
indentation.more_after = { '{' }
indentation.less_for = { '}' }
buffer = ActionBuffer!
buffer.text = '{\nfoo\n }\n'
lines = buffer.lines
buffer\style lines[1].start_pos, lines[2].end_pos, 'comment'
buffer\style lines[3].start_pos, lines[4].end_pos, 'string'
editor.buffer = buffer
indent!
assert.equals '{\nfoo\n }\n', buffer.text
indentation.more_after = { '{' }
mode.comment_syntax = '#'
buffer.text = " # I'm commenting thank you very much {\n# and still are\n"
indent!
assert.equals 2, lines[2].indentation
adjust any illegal indentation (not divisable by indent)
buffer.text = ' line\n two\n'
indent!
assert.equals ' line\n two\n', buffer.text
works on the current line if no selection is specified
indentation.more_after = { 'if' }
buffer.text = 'if\none\ntwo\n'
cursor.line = 2
mode\indent editor
assert.equals 'if\n one\ntwo\n', buffer.text
moves the cursor to the beginning of indentation if it would be positioned before
buffer.text = ' line1\n line2\n'
cursor.line = 2
mode\indent editor
assert.equals ' line1\n line2\n', buffer.text
assert.equals 3, cursor.column
(when .indentation.more_after patterns is set)
(.. and the previous line matches one of the patterns)
indents lines below matching lines with the currently set indent
indentation.more_after = { r'if', 'then' }
buffer.text = 'if\nbar\nthen\nfoo\n'
indent!
assert.equals 'if\n bar\nthen\n foo\n', buffer.text
(.. when .authoritive is not false)
adjusts lines with unwarranted greater indents to match the previous line
indentation.more_after = { 'if' }
buffer.text = 'line\n wat?\n'
indent!
assert.equals 'line\nwat?\n', buffer.text
(.. when .authoritive is false)
does not adjust lines with unwarranted greater indents to match the previous line
indentation.more_after = { 'if', authoritive: false }
buffer.text = 'line\n wat?\n'
indent!
assert.equals 'line\n wat?\n', buffer.text
(when .indentation.less_for is set)
(.. and the current line matches one of the patterns)
dedents the line one level below the previous line if it exists
indentation.less_for = { r'else', '}' }
buffer.text = ' bar\n else\n foo\n }\n'
indent!
assert.equals ' bar\n else\n foo\n}\n', buffer.text
(.. when .authoritive is not false)
adjusts lines with unwarranted smaller indents to match the previous line
indentation.less_for = { 'else' }
buffer.text = ' line\nwat?\n'
indent!
assert.equals ' line\n wat?\n', buffer.text
(.. when .authoritive is false)
does not adjust lines with unwarranted smaller indents to match the previous line
indentation.less_for = { 'else', authoritive: false }
buffer.text = ' line\nwat?\n'
indent!
assert.equals ' line\nwat?\n', buffer.text
(when .indentation.more_for is set)
(.. and the current line matches one of the patterns)
indents the line one level right of the previous line if it exists
indentation.more_for = { '^.' }
buffer.text = 'bar\n.foo\n'
indent!
assert.equals 'bar\n .foo\n', buffer.text
(when .indentation.same_after patterns is set)
(.. and the previous line matches one of the patterns)
indents lines below matching lines to have the same indent as the previous line
indentation.same_after = ',$'
buffer.text = ' foo,\nbar'
indent!
assert.equals ' foo,\n bar', buffer.text
(when more than one of .less_for, .more_after or .same_after are set)
they are weighed together
indentation.more_after = { '{' }
indentation.less_for = { '}' }
indentation.same_after = { ',$' }
buffer.text = ' {\n }'
indent!
assert.equals ' {\n }', buffer.text
buffer.text = ' {\n foo,}'
indent!
assert.equals ' {\n foo,}', buffer.text
(when a line is blank)
does not indent unless it is the current line
indentation.more_after = { '{' }
indentation.less_for = { '}' }
buffer.text = '{\n\n}'
indent!
assert.equals '{\n\n}', buffer.text
(.. and it is the current line)
indents according to patterns
indentation.more_after = { '{' }
indentation.less_for = { '}' }
buffer.text = '{\n\n}'
cursor.line = 2
mode\indent editor
assert.equals '{\n \n}', buffer.text
sets the same indent as for the previous line if nothing else is specified
buffer.text = ' line\n\n'
cursor.line = 2
mode\indent editor
assert.equals ' line\n \n', buffer.text
text = [[
liñe 1
liñe 2
liñe 3
]]
before_each ->
buffer.text = text
selection\set 1, lines[4].start_pos
(when .comment_syntax is not set)
does nothing
mode\comment editor
assert.equal text, buffer.text
(when .comment_syntax is set to a string)
before_each -> mode.comment_syntax = '--'
prefixes the selected lines with the prefix and a space, at the minimum indentation level
mode\comment editor
assert.equal [[
liñe 3
]], buffer.text
selection\remove!
cursor.pos = 1
mode\comment editor
assert.equal [[
liñe 2
liñe 3
]], buffer.text
honor leading tabs when use_tabs is true
buffer.config.use_tabs = true
buffer.text = '\tline1\n'
cursor.pos = 1
mode\comment editor
assert.equal '<TAB>-- line1\n', buffer.text\gsub('\t', '<TAB>')
keeps the cursor position
editor.selection.cursor = lines[3].start_pos + 2
mode\comment editor
assert.equal 6, cursor.column
(when .comment_syntax is set to a pair)
before_each -> mode.comment_syntax = {'/*', '*/'}
wraps each selected line with the pair, at the minimum indentation level
mode\comment editor
assert.equal [[
/* liñe 1 */
/* liñe 2 */
liñe 3
]], buffer.text
selection\remove!
cursor.pos = 1
mode\comment editor
assert.equal [[
/* liñe 1 */
liñe 2
liñe 3
]], buffer.text
keeps the cursor position
editor.selection.cursor = lines[3].start_pos + 2
mode\comment editor
assert.equal 6, cursor.column
(when .comment_syntax is not set)
does nothing
buffer.text = 'foo\nbar\n'
selection\set 1, lines[2].start_pos
mode\uncomment editor
assert.equal 'foo\nbar\n', buffer.text
(when .comment_syntax is set to a string)
before_each ->
buffer.mode.comment_syntax = '--'
buffer.text = [[
]]
selection\set 1, lines[3].start_pos
mode\uncomment editor
assert.equal [[
liñe 1
]], buffer.text
selection\remove!
cursor.line = 2
mode\uncomment editor
assert.equal [[
]], buffer.text
honor leading tabs when use_tabs is true
buffer.config.use_tabs = true
buffer.text = '\t-- line1\n'
cursor.pos = 1
mode\uncomment editor
assert.equal '<TAB>line1\n', buffer.text\gsub('\t', '<TAB>')
keeps the cursor position
editor.selection.cursor = lines[2].start_pos + 6
mode\uncomment editor
assert.equal 4, cursor.column
buffer.text = "line\n"
cursor.line = 1
mode\uncomment editor
assert.equal "line\n", buffer.text
(when .comment_syntax is set to a pair)
before_each ->
buffer.mode.comment_syntax = {'/*', '*/'}
buffer.text = [[
/* liñe 1 */
/* liñe 2 */
/*liñe 3*/
]]
selection\set 1, lines[3].start_pos
mode\uncomment editor
assert.equal [[
liñe 1
liñe 2
/*liñe 3*/
]], buffer.text
selection\remove!
cursor.line = 2
mode\uncomment editor
assert.equal [[
/* liñe 1 */
liñe 2
/*liñe 3*/
]], buffer.text
keeps the cursor position
editor.selection.cursor = lines[2].start_pos + 6
mode\uncomment editor
assert.equal 4, cursor.column
buffer.text = "line\n"
cursor.line = 1
mode\uncomment editor
assert.equal "line\n", buffer.text
(when mode does not provide .comment_syntax)
does nothing
buffer.text = '-- foo'
mode\toggle_comment editor
assert.equal '-- foo', buffer.text
(when mode provides .comment_syntax)
before_each -> buffer.mode.comment_syntax = '--'
buffer.text = ' -- foo\n\n -- foo2'
selection\select_all!
mode\toggle_comment editor
assert.equal ' foo\n\n foo2', buffer.text
buffer.text = 'foo\n-- foo2'
selection\select_all!
mode\toggle_comment editor
assert.equal '-- foo\n-- -- foo2', buffer.text
buffer.text = '-- foo\nfoo2'
selection\select_all!
mode\toggle_comment editor
assert.equal '-- -- foo\n-- foo2', buffer.text
buffer.text = 'foo\nfoo2'
selection\select_all!
mode\toggle_comment editor
assert.equal '-- foo\n-- foo2', buffer.text
indents the new line automatically given the indent patterns
indentation.more_after = { 'if' }
buffer.text = 'if'
cursor\eof!
editor\newline!
assert.equals 'if\n ', buffer.text
buffer.text = 'other'
cursor\eof!
editor\newline!
assert.equals 'other\n', buffer.text
structure()
assert_lines = (expected, actual) -> assert.same [l.nr for l in *expected], [l.nr for l in *actual]
returns a simple indentation-based structure
buffer.text = [[
header1
sub1
foo
bar
zed
froz
header2
sub2
]]
assert_lines {
lines[1]
lines[2]
lines[7]
}, mode\structure editor
the config variable indentation_structure_threshold determines when it stops
buffer.text = [[
header1
sub1
froz
header2
sub2
]]
buffer.config.indentation_structure_threshold = 2
assert_lines { lines[1], lines[4] }, mode\structure editor
disregards blank lines
buffer.text = '\n sub\n'
assert.same {}, mode\structure editor
(if a structure line is all non-alpha)
tries to use the previous line if that contains alpha characters
buffer.text = [[
int func(int arg)
{
froz();
}
]]
assert_lines { lines[1] }, mode\structure editor
skips the line altogether if the previous line does not contain alpha characters
buffer.text = [[
{
froz();
}
]]
assert_lines {}, mode\structure editor
patterns_match(text, patterns)
returns a boolean indicating whether <text> matches any of the specified patterns
assert.is_true mode\patterns_match 'foo', { 'foo' }
assert.is_false mode\patterns_match 'foo', { 'bar' }
accepts both Lua patterns and regexes
assert.is_true mode\patterns_match 'foo', { 'fo+' }
assert.is_true mode\patterns_match 'foo', { r'\\pLo*' }
a specifed pattern can be table containing both a positiv and a negative match
p = { 'foo', 'bar' }
assert.is_true mode\patterns_match 'foo zed', { p }
assert.is_false mode\patterns_match 'foo bar', { p }
when a newline is added
sets the indentation for the new line to the indentation of the previous non-blank line
buffer.text = ' 34\n\n78'
cursor.pos = 7
editor\newline!
assert.equals 2, editor.current_line.indentation
(when .code_blocks.multiline is present)
the code blocks are automatically enforced
mode.code_blocks = multiline: {
{ '%sdo$', '^%s*end', 'end' },
}
buffer.text = 'foo do'
cursor\eof!
editor\newline!
assert.equals 'foo do\n\nend\n', buffer.text
assert.equals 2, cursor.line
buffer.config.auto_format = false
mode.code_blocks = multiline: {
{ '%sdo$', '^%s*end', 'end' },
}
buffer.text = 'foo do'
cursor\eof!
editor\newline!
assert.equals 'foo do\n', buffer.text