let s:suite = themis#suite('html') let s:assert = themis#helper('assert') let s:emmet = themis#helper('emmet') function! s:suite.__setup() abort call s:emmet.setup() endfunction " expand abbreviation {{{ function! s:suite.__expand_abbreviation() let expand = themis#suite('expand abbreviation') function! expand.div() abort call s:assert.equals(s:emmet.expand_word('div', 'html'), "
\n") endfunction function! expand.div_id() abort call s:assert.equals(s:emmet.expand_word('div#wrapper', 'html'), "
\n") endfunction function! expand.div_class() abort call s:assert.equals(s:emmet.expand_word('div.box', 'html'), "
\n") endfunction function! expand.a_with_title() abort call s:assert.equals(s:emmet.expand_word('a[title=TITLE]', 'html'), "\n") endfunction function! expand.div_id_class() abort call s:assert.equals(s:emmet.expand_word('div#wrapper.box', 'html'), "
\n") endfunction function! expand.div_id_multi_class() abort call s:assert.equals(s:emmet.expand_word('div#wrapper.box.current', 'html'), "
\n") endfunction function! expand.div_id_multi_class_attrs() abort call s:assert.equals(s:emmet.expand_word('div#wrapper.box.current[title=TITLE rel]', 'html'), "
\n") endfunction function! expand.sibling() abort call s:assert.equals(s:emmet.expand_word('div#main+div#sub', 'html'), "
\n
\n") endfunction function! expand.child() abort call s:assert.equals(s:emmet.expand_word('div#main>div#sub', 'html'), "
\n\t
\n
\n") endfunction function! expand.html_xt_complex() abort call s:assert.equals(s:emmet.expand_word('html:xt>div#header>div#logo+ul#nav>li.item-$*5>a', 'html'), "\n\n\n\t\n\t\n\n\n\t
\n\t\t
\n\t\t\n\t
\n\t\n\n") endfunction function! expand.ol_li_multiplier() abort call s:assert.equals(s:emmet.expand_word('ol>li*2', 'html'), "
    \n\t
  1. \n\t
  2. \n
\n") endfunction function! expand.a_default_attr() abort call s:assert.equals(s:emmet.expand_word('a', 'html'), "\n") endfunction function! expand.obj_alias() abort call s:assert.equals(s:emmet.expand_word('obj', 'html'), "\n") endfunction function! expand.cc_ie6_complex() abort call s:assert.equals(s:emmet.expand_word('cc:ie6>p+blockquote#sample$.so.many.classes*2', 'html'), "") endfunction function! expand.html_4t_complex() abort call s:assert.equals(s:emmet.expand_word('html:4t>div#wrapper>div#header+div#contents+div#footer', 'html'), "\n\n\n\t\n\t\n\n\n\t
\n\t\t
\n\t\t
\n\t\t
\n\t
\n\t\n\n") endfunction function! expand.a_href_class_id() abort call s:assert.equals(s:emmet.expand_word('a[href=http://www.google.com/].foo#hoge', 'html'), "\n") endfunction function! expand.a_href_text() abort call s:assert.equals(s:emmet.expand_word('a[href=http://www.google.com/]{Google}', 'html'), "Google\n") endfunction function! expand.text_only() abort call s:assert.equals(s:emmet.expand_word('{Emmet}', 'html'), 'Emmet') endfunction function! expand.a_plus_b() abort call s:assert.equals(s:emmet.expand_word('a+b', 'html'), "\n\n") endfunction function! expand.climb_up_lt() abort call s:assert.equals(s:emmet.expand_word('a>b>i\n") endfunction function! expand.climb_up_caret() abort call s:assert.equals(s:emmet.expand_word('a>b>i^b', 'html'), "\n") endfunction function! expand.climb_up_double_lt() abort call s:assert.equals(s:emmet.expand_word('a>b>i<\n\n") endfunction function! expand.climb_up_double_caret() abort call s:assert.equals(s:emmet.expand_word('a>b>i^^b', 'html'), "\n\n") endfunction function! expand.blockquote_climb_up_lt() abort call s:assert.equals(s:emmet.expand_word('blockquote>b>i<\n\t\n\n\n") endfunction function! expand.blockquote_climb_up_caret() abort call s:assert.equals(s:emmet.expand_word('blockquote>b>i^^b', 'html'), "
\n\t\n
\n\n") endfunction function! expand.multi_attr() abort call s:assert.equals(s:emmet.expand_word('a[href=foo][class=bar]', 'html'), "\n") endfunction function! expand.complex_attrs_multiplier() abort call s:assert.equals(s:emmet.expand_word('a[a=b][b=c=d][e]{foo}*2', 'html'), "foo\nfoo\n") endfunction function! expand.attrs_multiplier_text_after() abort call s:assert.equals(s:emmet.expand_word('a[a=b][b=c=d][e]*2{foo}', 'html'), "\n\nfoo") endfunction function! expand.multiplier_text_tag() abort call s:assert.equals(s:emmet.expand_word('a*2{foo}a', 'html'), "\n\nfoo\n") endfunction function! expand.text_multiplier_child() abort call s:assert.equals(s:emmet.expand_word('a{foo}*2>b', 'html'), "foo\nfoo\n") endfunction function! expand.multiplier_text_child() abort call s:assert.equals(s:emmet.expand_word('a*2{foo}>b', 'html'), "\n\nfoo") endfunction function! expand.table_complex() abort call s:assert.equals(s:emmet.expand_word('table>tr>td.name#foo+td*3', 'html'), "\n\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\n
\n") endfunction function! expand.sibling_ids() abort call s:assert.equals(s:emmet.expand_word('div#header+div#footer', 'html'), "
\n
\n") endfunction function! expand.implicit_div_sibling() abort call s:assert.equals(s:emmet.expand_word('#header+div#footer', 'html'), "
\n
\n") endfunction function! expand.climb_up_with_text_lt() abort call s:assert.equals(s:emmet.expand_word('#header>ul>li\n\t
    \n\t\t
  • \n\t
\n\t

Footer

\n\n") endfunction function! expand.climb_up_with_text_caret() abort call s:assert.equals(s:emmet.expand_word('#header>ul>li^p{Footer}', 'html'), "
\n\t
    \n\t\t
  • \n\t
\n\t

Footer

\n
\n") endfunction function! expand.dollar_padding() abort call s:assert.equals(s:emmet.expand_word('a#foo$$$*3', 'html'), "\n\n\n") endfunction function! expand.ul_expando() abort call s:assert.equals(s:emmet.expand_word('ul+', 'html'), "
    \n\t
  • \n
\n") endfunction function! expand.table_expando() abort call s:assert.equals(s:emmet.expand_word('table+', 'html'), "\n\t\n\t\t\n\t\n
\n") endfunction function! expand.header_climb_content_lt() abort call s:assert.equals(s:emmet.expand_word('#header>li<#content', 'html'), "
\n\t
  • \n
    \n
    \n") endfunction function! expand.header_climb_content_caret() abort call s:assert.equals(s:emmet.expand_word('#header>li^#content', 'html'), "
    \n\t
  • \n
    \n
    \n") endfunction function! expand.group_climb_lt() abort call s:assert.equals(s:emmet.expand_word('(#header>li)<#content', 'html'), "
    \n\t
  • \n
    \n
    \n") endfunction function! expand.group_climb_caret() abort call s:assert.equals(s:emmet.expand_word('(#header>li)^#content', 'html'), "
    \n\t
  • \n
    \n
    \n") endfunction function! expand.double_climb_lt() abort call s:assert.equals(s:emmet.expand_word('a>b>i<\n
    \n") endfunction function! expand.double_climb_caret() abort call s:assert.equals(s:emmet.expand_word('a>b>i^^div', 'html'), "\n
    \n") endfunction function! expand.group_sibling() abort call s:assert.equals(s:emmet.expand_word('(#header>h1)+#content+#footer', 'html'), "
    \n\t

    \n
    \n
    \n
    \n") endfunction function! expand.complex_nested_groups() abort call s:assert.equals(s:emmet.expand_word('(#header>h1)+(#content>(#main>h2+div#entry$.section*5>(h3>a)+div>p*3+ul+)+(#utilities))+(#footer>address)', 'html'), "
    \n\t

    \n
    \n
    \n\t
    \n\t\t

    \n\t\t
    \n\t\t\t

    \n\t\t\t
    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t
      \n\t\t\t\t\t
    • \n\t\t\t\t
    \n\t\t\t
    \n\t\t
    \n\t\t
    \n\t\t\t

    \n\t\t\t
    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t
      \n\t\t\t\t\t
    • \n\t\t\t\t
    \n\t\t\t
    \n\t\t
    \n\t\t
    \n\t\t\t

    \n\t\t\t
    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t
      \n\t\t\t\t\t
    • \n\t\t\t\t
    \n\t\t\t
    \n\t\t
    \n\t\t
    \n\t\t\t

    \n\t\t\t
    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t
      \n\t\t\t\t\t
    • \n\t\t\t\t
    \n\t\t\t
    \n\t\t
    \n\t\t
    \n\t\t\t

    \n\t\t\t
    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t

    \n\t\t\t\t
      \n\t\t\t\t\t
    • \n\t\t\t\t
    \n\t\t\t
    \n\t\t
    \n\t
    \n\t
    \n
    \n
    \n\t
    \n
    \n") endfunction function! expand.nested_multiplier_groups() abort call s:assert.equals(s:emmet.expand_word('(div>(ul*2)*2)+(#utilities)', 'html'), "
    \n\t
      \n\t
        \n\t
          \n\t
            \n
            \n
            \n") endfunction function! expand.table_multiplier_group() abort call s:assert.equals(s:emmet.expand_word('table>(tr>td*3)*4', 'html'), "\n\t\n\t\t\n\t\t\n\t\t\n\t\n\t\n\t\t\n\t\t\n\t\t\n\t\n\t\n\t\t\n\t\t\n\t\t\n\t\n\t\n\t\t\n\t\t\n\t\t\n\t\n
            \n") endfunction function! expand.nested_multiplier_groups_deep() abort call s:assert.equals(s:emmet.expand_word('(((a#foo+a#bar)*2)*3)', 'html'), "\n\n\n\n\n\n\n\n\n\n\n\n") endfunction function! expand.multiplier_with_child() abort call s:assert.equals(s:emmet.expand_word('div#box$*3>h3+p*2', 'html'), "
            \n\t

            \n\t

            \n\t

            \n
            \n
            \n\t

            \n\t

            \n\t

            \n
            \n
            \n\t

            \n\t

            \n\t

            \n
            \n") endfunction function! expand.dollar_multi_class() abort call s:assert.equals(s:emmet.expand_word('div#box.foo$$$.bar$$$*3', 'html'), "
            \n
            \n
            \n") endfunction function! expand.escape_filter() abort call s:assert.equals(s:emmet.expand_word('div#box$*3>h3+p.bar*2|e', 'html'), "<div id=\"box1\">\n\t<h3></h3>\n\t<p class=\"bar\"></p>\n\t<p class=\"bar\"></p>\n</div>\n<div id=\"box2\">\n\t<h3></h3>\n\t<p class=\"bar\"></p>\n\t<p class=\"bar\"></p>\n</div>\n<div id=\"box3\">\n\t<h3></h3>\n\t<p class=\"bar\"></p>\n\t<p class=\"bar\"></p>\n</div>\n") endfunction function! expand.comment_filter() abort call s:assert.equals(s:emmet.expand_word('div>div#page>p.title+p|c', 'html'), "
            \n\t\n\t
            \n\t\t\n\t\t

            \n\t\t\n\t\t

            \n\t
            \n\t\n
            \n") endfunction function! expand.single_line_filter() abort call s:assert.equals(s:emmet.expand_word('kbd*2|s', 'html'), '') endfunction function! expand.link_css() abort call s:assert.equals(s:emmet.expand_word('link:css', 'html'), "\n") endfunction function! expand.attr_with_quote() abort call s:assert.equals(s:emmet.expand_word("a[title=\"Hello', world\" rel]", 'html'), "\n") endfunction function! expand.child_with_text() abort call s:assert.equals(s:emmet.expand_word('div>a#foo{bar}', 'html'), "\n") endfunction function! expand.class_with_text() abort call s:assert.equals(s:emmet.expand_word('.content{Hello!}', 'html'), "
            Hello!
            \n") endfunction function! expand.logo_group_siblings() abort call s:assert.equals(s:emmet.expand_word('div.logo+(div#navigation)+(div#links)', 'html'), "
            \n
            \n
            \n") endfunction function! expand.mixed_text_and_tags() abort call s:assert.equals(s:emmet.expand_word('h1{header}+{Text}+a[href=http://link.org]{linktext}+{again some text}+a[href=http://anoterlink.org]{click me!}+{some final text}', 'html'), "

            header

            \nTextlinktext\nagain some textclick me!\nsome final text") endfunction function! expand.ampersand_text() abort call s:assert.equals(s:emmet.expand_word('a{&}+div{&&}', 'html'), "&\n
            &&
            \n") endfunction function! expand.span_after_tag() abort let res = s:emmet.expand_in_buffer('span$$$$\,$$$$', 'html', '') call s:assert.equals(res, '') endfunction function! expand.span_after_text() abort let res = s:emmet.expand_in_buffer('foo span$$$$\,$$$$', 'html', 'foo ') call s:assert.equals(res, 'foo ') endfunction function! expand.span_after_text_before_text() abort let res = s:emmet.expand_in_buffer('foo span$$$$\,$$$$ bar', 'html', 'foo bar') call s:assert.equals(res, 'foo bar') endfunction function! expand.visual_word_wrap() abort let res = s:emmet.expand_in_buffer("foo $$$$\\ve\\,p\\$$$$bar baz", 'html', 'foo

            bar

            baz') call s:assert.equals(res, 'foo

            bar

            baz') endfunction function! expand.visual_multi_word_wrap() abort let res = s:emmet.expand_in_buffer("foo $$$$\\vee\\,p\\$$$$bar baz", 'html', 'foo

            bar baz

            ') call s:assert.equals(res, 'foo

            bar baz

            ') endfunction function! expand.complex_nested() abort let res = s:emmet.expand_in_buffer("f div.boxes>article.box2>header>(hgroup>h2{aaa}+h3{bbb})+p{ccc}$$$$", 'html', "f
            \n\t
            \n\t\t
            \n\t\t\t
            \n\t\t\t\t

            aaa

            \n\t\t\t\t

            bbb

            \n\t\t\t
            \n\t\t\t

            ccc

            \n\t\t
            \n\t
            \n
            ") call s:assert.equals(res, "f
            \n\t
            \n\t\t
            \n\t\t\t
            \n\t\t\t\t

            aaa

            \n\t\t\t\t

            bbb

            \n\t\t\t
            \n\t\t\t

            ccc

            \n\t\t
            \n\t
            \n
            ") endfunction function! expand.complex_boxes() abort call s:assert.equals(s:emmet.expand_word("div.boxes>(div.box2>section>h2{a}+p{b})+(div.box1>section>h2{c}+p{d}+p{e}+(bq>h2{f}+h3{g})+p{h})", 'html'), "
            \n\t
            \n\t\t
            \n\t\t\t

            a

            \n\t\t\t

            b

            \n\t\t
            \n\t
            \n\t
            \n\t\t
            \n\t\t\t

            c

            \n\t\t\t

            d

            \n\t\t\t

            e

            \n\t\t\t
            \n\t\t\t\t

            f

            \n\t\t\t\t

            g

            \n\t\t\t
            \n\t\t\t

            h

            \n\t\t
            \n\t
            \n
            \n") endfunction function! expand.label_input_group() abort call s:assert.equals(s:emmet.expand_word('(div>(label+input))+div', 'html'), "
            \n\t\n\t\n
            \n
            \n") endfunction function! expand.visual_wrap_multiplier() abort let res = s:emmet.expand_in_buffer("test1\ntest2\ntest3$$$$\\ggVG\\,ul>li>span*>a\\$$$$", 'html', "") call s:assert.equals(res, "") endfunction function! expand.visual_wrap_input() abort let res = s:emmet.expand_in_buffer("test1\ntest2\ntest3$$$$\\ggVG\\,input[type=input value=$#]*\\$$$$", 'html', "\n\n") call s:assert.equals(res, "\n\n") endfunction function! expand.visual_wrap_div_id() abort let res = s:emmet.expand_in_buffer("test1\ntest2\ntest3$$$$\\ggVG\\,div[id=$#]*\\$$$$", 'html', "
            \n
            \n
            ") call s:assert.equals(res, "
            \n
            \n
            ") endfunction function! expand.nested_id_dollar() abort call s:assert.equals(s:emmet.expand_word('div#id-$*5>div#id2-$', 'html'), "
            \n\t
            \n
            \n
            \n\t
            \n
            \n
            \n\t
            \n
            \n
            \n\t
            \n
            \n
            \n\t
            \n
            \n") endfunction function! expand.implicit_child_attr() abort call s:assert.equals(s:emmet.expand_word('.foo>[bar=2]>.baz', 'html'), "
            \n\t
            \n\t\t
            \n\t
            \n
            \n") endfunction function! expand.text_dollar() abort call s:assert.equals(s:emmet.expand_word('{test case $ }*3', 'html'), 'test case 1 test case 2 test case 3 ') endfunction function! expand.text_dollar_newline() abort call s:assert.equals(s:emmet.expand_word('{test case $${nr}}*3', 'html'), "test case 1\ntest case 2\ntest case 3\n") endfunction function! expand.text_escaped_dollar() abort call s:assert.equals(s:emmet.expand_word('{test case \$ }*3', 'html'), 'test case $ test case $ test case $ ') endfunction function! expand.text_dollar_padding() abort call s:assert.equals(s:emmet.expand_word('{test case $$$ }*3', 'html'), 'test case 001 test case 002 test case 003 ') endfunction function! expand.title_dollar_hash() abort call s:assert.equals(s:emmet.expand_word('a[title=$#]{foo}', 'html'), "foo\n") endfunction function! expand.span_item_dollar_text() abort call s:assert.equals(s:emmet.expand_word('span.item$*2>{item $}', 'html'), "item 1\nitem 2\n") endfunction function! expand.visual_wrap_indented() abort let res = s:emmet.expand_in_buffer("\t
            \n\t\tnav link\n\t
            $$$$\\ggVG\\,div\\$$$$", 'html', "\t
            \n\t\t
            \n\t\t\tnav link\n\t\t
            \n\t
            ") call s:assert.equals(res, "\t
            \n\t\t
            \n\t\t\tnav link\n\t\t
            \n\t
            ") endfunction function! expand.expand_inside_tag() abort let res = s:emmet.expand_in_buffer('a$$$$', 'html', '') call s:assert.equals(res, '') endfunction function! expand.bem_filter() abort call s:assert.equals(s:emmet.expand_word('form.search-form._wide>input.-query-string+input:s.-btn_large|bem', 'html'), "
            \n\t\n\t\n
            \n") endfunction function! expand.fieldset_legend_label() abort call s:assert.equals(s:emmet.expand_word('form>fieldset>legend+(label>input[type="checkbox"])*3', 'html'), "
            \n\t
            \n\t\t\n\t\t\n\t\t\n\t\t\n\t
            \n
            \n") endfunction endfunction " }}} " split join tag {{{ function! s:suite.__split_join_tag() let split_join = themis#suite('split join tag') function! split_join.join_tag() abort let res = s:emmet.expand_in_buffer("
            \n\t$$$$\\j$$$$\n
            ", 'html', "
            \n\t\n
            ") call s:assert.equals(res, "
            \n\t\n
            ") endfunction function! split_join.split_tag() abort let res = s:emmet.expand_in_buffer("
            \n\tj$$$$/>\n
            ", 'html', "
            \n\t\n
            ") call s:assert.equals(res, "
            \n\t\n
            ") endfunction function! split_join.join_with_complex_attr() abort let res = s:emmet.expand_in_buffer("
            500)\">test$$$$\\j$$$$/>\n
            ", 'html', '
            ') call s:assert.equals(res, '
            ') endfunction function! split_join.split_custom_tag() abort let res = s:emmet.expand_in_buffer("
            \n\tj$$$$/>\n
            ", 'html', "
            \n\t\n
            ") call s:assert.equals(res, "
            \n\t\n
            ") endfunction endfunction " }}} " toggle comment {{{ function! s:suite.__toggle_comment() let comment = themis#suite('toggle comment') function! comment.add_comment() abort let res = s:emmet.expand_in_buffer("
            \n\t$$$$\\/$$$$\n
            ", 'html', "
            \n\t\n
            ") call s:assert.equals(res, "
            \n\t\n
            ") endfunction function! comment.remove_comment() abort let res = s:emmet.expand_in_buffer("
            \n\t\n
            ", 'html', "
            \n\t\n
            ") call s:assert.equals(res, "
            \n\t\n
            ") endfunction endfunction " }}} " image size {{{ function! s:suite.__image_size() let imgsize = themis#suite('image size') function! imgsize.remote_png() abort let res = s:emmet.expand_in_buffer("img[src=http://mattn.kaoriya.net/images/logo.png]$$$$\\,\\i$$$$", 'html', '') call s:assert.equals(res, '') endfunction function! imgsize.local_missing() abort let res = s:emmet.expand_in_buffer("img[src=/logo.png]$$$$\\,\\i$$$$", 'html', '') call s:assert.equals(res, '') endfunction function! imgsize.overwrite_existing() abort let res = s:emmet.expand_in_buffer("img[src=http://mattn.kaoriya.net/images/logo.png width=foo height=bar]$$$$\\,\\i$$$$", 'html', '') call s:assert.equals(res, '') endfunction endfunction " }}} " move next prev {{{ function! s:suite.__move_next_prev() let move = themis#suite('move next prev') function! move.move_to_third_attr() abort let res = s:emmet.expand_in_buffer("foo+bar+baz[dankogai=\"\"]$$$$\\,\\gg0\\n\\n\\n\\Byw:%d _\\p$$$$", 'html', 'dankogai') call s:assert.equals(res, 'dankogai') endfunction endfunction " }}} " contains dash in attributes {{{ function! s:suite.__dash_in_attributes() let dash = themis#suite('contains dash in attributes') function! dash.foo_bar_attr() abort call s:assert.equals(s:emmet.expand_word('div[foo-bar="baz"]', 'html'), "
            \n") endfunction endfunction " }}} " default attributes {{{ function! s:suite.__default_attributes() let defattr = themis#suite('default attributes') function! defattr.a_href_shorthand() abort call s:assert.equals(s:emmet.expand_word('p.title>a[/hoge/]', 'html'), "

            \n") endfunction function! defattr.script_src() abort call s:assert.equals(s:emmet.expand_word('script[jquery.js]', 'html'), "\n") endfunction endfunction " }}} " multiple group {{{ function! s:suite.__multiple_group() let group = themis#suite('multiple group') function! group.outer_inner() abort call s:assert.equals(s:emmet.expand_word('.outer$*3>.inner$*2', 'html'), "
            \n\t
            \n\t
            \n
            \n
            \n\t
            \n\t
            \n
            \n
            \n\t
            \n\t
            \n
            \n") endfunction endfunction " }}} " group itemno {{{ function! s:suite.__group_itemno() let itemno = themis#suite('group itemno') function! itemno.dl_dt_dd() abort call s:assert.equals(s:emmet.expand_word('dl>(dt{$}+dd)*3', 'html'), "
            \n\t
            1
            \n\t
            \n\t
            2
            \n\t
            \n\t
            3
            \n\t
            \n
            \n") endfunction function! itemno.nested_multiplier() abort call s:assert.equals(s:emmet.expand_word('(div[attr=$]*3)*3', 'html'), "
            \n
            \n
            \n
            \n
            \n
            \n
            \n
            \n
            \n") endfunction endfunction " }}} " update tag {{{ function! s:suite.__update_tag() let update = themis#suite('update tag') function! update.add_class() abort let res = s:emmet.expand_in_buffer("u.global\\$$$$3>", 'html', '

            ') call s:assert.equals(res, '

            ') endfunction function! update.add_class_preserve_attr() abort let res = s:emmet.expand_in_buffer("u.btn\\$$$$ disabled>", 'html', '') call s:assert.equals(res, '') endfunction endfunction " }}} " base value {{{ function! s:suite.__base_value() let base = themis#suite('base value') function! base.base_zero() abort call s:assert.equals(s:emmet.expand_word('ul>li#id$@0*3', 'html'), "
              \n\t
            • \n\t
            • \n\t
            • \n
            \n") endfunction endfunction " }}}