mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-03 17:24:29 +00:00 
			
		
		
		
	vim-patch:9.1.1056: Vim doesn't highlight to be inserted text when completing (#32251)
Problem:  Vim doesn't highlight to be inserted text when completing
Solution: Add support for the "preinsert" 'completeopt' value
          (glepnir)
Support automatically inserting the currently selected candidate word
that does not belong to the latter part of the leader.
fixes: vim/vim#3433
closes: vim/vim#16403
edd4ac3e89
Co-authored-by: glepnir <glephunter@gmail.com>
			
			
This commit is contained in:
		@@ -188,6 +188,7 @@ information.
 | 
			
		||||
  vim_strcat strncat                                     xstrlcat
 | 
			
		||||
  VIM_ISWHITE                                          ascii_iswhite
 | 
			
		||||
  IS_WHITE_OR_NUL                                  ascii_iswhite_or_nul
 | 
			
		||||
  IS_WHITE_NL_OR_NUL                              ascii_iswhite_nl_or_nul
 | 
			
		||||
  vim_isalpha                                           mb_isalpha
 | 
			
		||||
  vim_isNormalIDc                                      ascii_isident
 | 
			
		||||
  vim_islower vim_isupper                          mb_islower mb_isupper
 | 
			
		||||
 
 | 
			
		||||
@@ -309,6 +309,7 @@ LUA
 | 
			
		||||
OPTIONS
 | 
			
		||||
 | 
			
		||||
• 'completeopt' flag "fuzzy" enables |fuzzy-matching| during |ins-completion|.
 | 
			
		||||
• 'completeopt' flag "preinsert" highlights text to be inserted.
 | 
			
		||||
• 'messagesopt' configures |:messages| and |hit-enter| prompt.
 | 
			
		||||
• 'tabclose' controls which tab page to focus when closing a tab page.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1575,6 +1575,12 @@ A jump table for the options with a short description can be found at |Q_op|.
 | 
			
		||||
		    scores when "fuzzy" is enabled. Candidates will appear
 | 
			
		||||
		    in their original order.
 | 
			
		||||
 | 
			
		||||
	   preinsert
 | 
			
		||||
		    Preinsert the portion of the first candidate word that is
 | 
			
		||||
		    not part of the current completion leader and using the
 | 
			
		||||
		    |hl-ComplMatchIns| highlight group. Does not work when
 | 
			
		||||
		    "fuzzy" is also included.
 | 
			
		||||
 | 
			
		||||
						*'completeslash'* *'csl'*
 | 
			
		||||
'completeslash' 'csl'	string	(default "")
 | 
			
		||||
			local to buffer
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								runtime/lua/vim/_meta/options.lua
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								runtime/lua/vim/_meta/options.lua
									
									
									
										generated
									
									
									
								
							@@ -1102,6 +1102,12 @@ vim.go.cia = vim.go.completeitemalign
 | 
			
		||||
--- 	    scores when "fuzzy" is enabled. Candidates will appear
 | 
			
		||||
--- 	    in their original order.
 | 
			
		||||
---
 | 
			
		||||
---    preinsert
 | 
			
		||||
--- 	    Preinsert the portion of the first candidate word that is
 | 
			
		||||
--- 	    not part of the current completion leader and using the
 | 
			
		||||
--- 	    `hl-ComplMatchIns` highlight group. Does not work when
 | 
			
		||||
--- 	    "fuzzy" is also included.
 | 
			
		||||
---
 | 
			
		||||
--- @type string
 | 
			
		||||
vim.o.completeopt = "menu,preview"
 | 
			
		||||
vim.o.cot = vim.o.completeopt
 | 
			
		||||
 
 | 
			
		||||
@@ -103,6 +103,15 @@ static inline bool ascii_iswhite_or_nul(int c)
 | 
			
		||||
  return ascii_iswhite(c) || c == NUL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Checks if `c` is a space or tab or newline character or NUL.
 | 
			
		||||
///
 | 
			
		||||
/// @see {ascii_isdigit}
 | 
			
		||||
static inline bool ascii_iswhite_nl_or_nul(int c)
 | 
			
		||||
  FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE
 | 
			
		||||
{
 | 
			
		||||
  return ascii_iswhite(c) || c == '\n' || c == NUL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Check whether character is a decimal digit.
 | 
			
		||||
///
 | 
			
		||||
/// Library isdigit() function is officially locale-dependent and, for
 | 
			
		||||
 
 | 
			
		||||
@@ -609,7 +609,10 @@ static int insert_execute(VimState *state, int key)
 | 
			
		||||
               && (s->c == CAR || s->c == K_KENTER || s->c == NL)))
 | 
			
		||||
          && stop_arrow() == OK) {
 | 
			
		||||
        ins_compl_delete(false);
 | 
			
		||||
        ins_compl_insert(false);
 | 
			
		||||
        ins_compl_insert(false, false);
 | 
			
		||||
      } else if (ascii_iswhite_nl_or_nul(s->c) && ins_compl_preinsert_effect()) {
 | 
			
		||||
        // Delete preinserted text when typing special chars
 | 
			
		||||
        ins_compl_delete(false);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -1781,12 +1781,33 @@ int ins_compl_len(void)
 | 
			
		||||
  return compl_length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Return true when preinsert is set otherwise FALSE.
 | 
			
		||||
static bool ins_compl_has_preinsert(void)
 | 
			
		||||
{
 | 
			
		||||
  return (get_cot_flags() & (kOptCotFlagFuzzy|kOptCotFlagPreinsert)) == kOptCotFlagPreinsert;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns true if the pre-insert effect is valid and the cursor is within
 | 
			
		||||
/// the `compl_ins_end_col` range.
 | 
			
		||||
bool ins_compl_preinsert_effect(void)
 | 
			
		||||
{
 | 
			
		||||
  if (!ins_compl_has_preinsert()) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return curwin->w_cursor.col < compl_ins_end_col;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete one character before the cursor and show the subset of the matches
 | 
			
		||||
/// that match the word that is now before the cursor.
 | 
			
		||||
/// Returns the character to be used, NUL if the work is done and another char
 | 
			
		||||
/// to be got from the user.
 | 
			
		||||
int ins_compl_bs(void)
 | 
			
		||||
{
 | 
			
		||||
  if (ins_compl_preinsert_effect()) {
 | 
			
		||||
    ins_compl_delete(false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  char *line = get_cursor_line_ptr();
 | 
			
		||||
  char *p = line + curwin->w_cursor.col;
 | 
			
		||||
  MB_PTR_BACK(line, p);
 | 
			
		||||
@@ -1872,8 +1893,13 @@ static void ins_compl_new_leader(void)
 | 
			
		||||
  ins_compl_show_pum();
 | 
			
		||||
 | 
			
		||||
  // Don't let Enter select the original text when there is no popup menu.
 | 
			
		||||
  if (compl_match_array == NULL) {
 | 
			
		||||
    compl_enter_selects = false;
 | 
			
		||||
  } else if (ins_compl_has_preinsert() && compl_leader.size > 0) {
 | 
			
		||||
    ins_compl_insert(false, true);
 | 
			
		||||
  }
 | 
			
		||||
  // Don't let Enter select when use user function and refresh_always is set
 | 
			
		||||
  if (compl_match_array == NULL || ins_compl_refresh_always()) {
 | 
			
		||||
  if (ins_compl_refresh_always()) {
 | 
			
		||||
    compl_enter_selects = false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1896,6 +1922,10 @@ void ins_compl_addleader(int c)
 | 
			
		||||
{
 | 
			
		||||
  int cc;
 | 
			
		||||
 | 
			
		||||
  if (ins_compl_preinsert_effect()) {
 | 
			
		||||
    ins_compl_delete(false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (stop_arrow() == FAIL) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
@@ -3696,6 +3726,12 @@ void ins_compl_delete(bool new_leader)
 | 
			
		||||
  // In insert mode: Delete the typed part.
 | 
			
		||||
  // In replace mode: Put the old characters back, if any.
 | 
			
		||||
  int col = compl_col + (compl_status_adding() ? compl_length : orig_col);
 | 
			
		||||
  bool has_preinsert = ins_compl_preinsert_effect();
 | 
			
		||||
  if (has_preinsert) {
 | 
			
		||||
    col = compl_col + (int)ins_compl_leader_len() - compl_length;
 | 
			
		||||
    curwin->w_cursor.col = compl_ins_end_col;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((int)curwin->w_cursor.col > col) {
 | 
			
		||||
    if (stop_arrow() == FAIL) {
 | 
			
		||||
      return;
 | 
			
		||||
@@ -3713,15 +3749,24 @@ void ins_compl_delete(bool new_leader)
 | 
			
		||||
 | 
			
		||||
/// Insert the new text being completed.
 | 
			
		||||
/// "in_compl_func" is true when called from complete_check().
 | 
			
		||||
void ins_compl_insert(bool in_compl_func)
 | 
			
		||||
/// "move_cursor" is used when 'completeopt' includes "preinsert" and when true
 | 
			
		||||
/// cursor needs to move back from the inserted text to the compl_leader.
 | 
			
		||||
void ins_compl_insert(bool in_compl_func, bool move_cursor)
 | 
			
		||||
{
 | 
			
		||||
  int compl_len = get_compl_len();
 | 
			
		||||
  bool preinsert = ins_compl_has_preinsert();
 | 
			
		||||
  char *str = compl_shown_match->cp_str.data;
 | 
			
		||||
  size_t leader_len = ins_compl_leader_len();
 | 
			
		||||
 | 
			
		||||
  // Make sure we don't go over the end of the string, this can happen with
 | 
			
		||||
  // illegal bytes.
 | 
			
		||||
  if (compl_len < (int)compl_shown_match->cp_str.size) {
 | 
			
		||||
    ins_compl_insert_bytes(compl_shown_match->cp_str.data + compl_len, -1);
 | 
			
		||||
    ins_compl_insert_bytes(str + compl_len, -1);
 | 
			
		||||
    if (preinsert && move_cursor) {
 | 
			
		||||
      curwin->w_cursor.col -= (colnr_T)(strlen(str) - leader_len);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  compl_used_match = !match_at_original_text(compl_shown_match);
 | 
			
		||||
  compl_used_match = !(match_at_original_text(compl_shown_match) || preinsert);
 | 
			
		||||
 | 
			
		||||
  dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
 | 
			
		||||
  set_vim_var_dict(VV_COMPLETED_ITEM, dict);
 | 
			
		||||
@@ -3923,6 +3968,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
 | 
			
		||||
  unsigned cur_cot_flags = get_cot_flags();
 | 
			
		||||
  bool compl_no_insert = (cur_cot_flags & kOptCotFlagNoinsert) != 0;
 | 
			
		||||
  bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
 | 
			
		||||
  bool compl_preinsert = ins_compl_has_preinsert();
 | 
			
		||||
 | 
			
		||||
  // When user complete function return -1 for findstart which is next
 | 
			
		||||
  // time of 'always', compl_shown_match become NULL.
 | 
			
		||||
@@ -3967,13 +4013,13 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Insert the text of the new completion, or the compl_leader.
 | 
			
		||||
  if (compl_no_insert && !started) {
 | 
			
		||||
  if (compl_no_insert && !started && !compl_preinsert) {
 | 
			
		||||
    ins_compl_insert_bytes(compl_orig_text.data + get_compl_len(), -1);
 | 
			
		||||
    compl_used_match = false;
 | 
			
		||||
    restore_orig_extmarks();
 | 
			
		||||
  } else if (insert_match) {
 | 
			
		||||
    if (!compl_get_longest || compl_used_match) {
 | 
			
		||||
      ins_compl_insert(in_compl_func);
 | 
			
		||||
      ins_compl_insert(in_compl_func, true);
 | 
			
		||||
    } else {
 | 
			
		||||
      assert(compl_leader.data != NULL);
 | 
			
		||||
      ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1);
 | 
			
		||||
 
 | 
			
		||||
@@ -1494,6 +1494,7 @@ local options = {
 | 
			
		||||
        'noselect',
 | 
			
		||||
        'fuzzy',
 | 
			
		||||
        'nosort',
 | 
			
		||||
        'preinsert',
 | 
			
		||||
      },
 | 
			
		||||
      flags = true,
 | 
			
		||||
      deny_duplicates = true,
 | 
			
		||||
@@ -1542,6 +1543,12 @@ local options = {
 | 
			
		||||
           nosort   Disable sorting of completion candidates based on fuzzy
 | 
			
		||||
        	    scores when "fuzzy" is enabled. Candidates will appear
 | 
			
		||||
        	    in their original order.
 | 
			
		||||
 | 
			
		||||
           preinsert
 | 
			
		||||
        	    Preinsert the portion of the first candidate word that is
 | 
			
		||||
        	    not part of the current completion leader and using the
 | 
			
		||||
        	    |hl-ComplMatchIns| highlight group. Does not work when
 | 
			
		||||
        	    "fuzzy" is also included.
 | 
			
		||||
      ]=],
 | 
			
		||||
      full_name = 'completeopt',
 | 
			
		||||
      list = 'onecomma',
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,7 @@ let test_values = {
 | 
			
		||||
      \		['xxx', 'help,nofile']],
 | 
			
		||||
      \ 'clipboard': [['', 'unnamed'], ['xxx', '\ze*', 'exclude:\\%(']],
 | 
			
		||||
      \ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup',
 | 
			
		||||
      \		'noinsert', 'noselect', 'fuzzy', 'menu,longest'],
 | 
			
		||||
      \		'noinsert', 'noselect', 'fuzzy', 'preinsert', 'menu,longest'],
 | 
			
		||||
      \		['xxx', 'menu,,,longest,']],
 | 
			
		||||
      \ 'encoding': [['utf8'], []],
 | 
			
		||||
      \ 'foldcolumn': [[0, 1, 4, 'auto', 'auto:1', 'auto:9'], [-1, 13, 999]],
 | 
			
		||||
@@ -186,7 +186,7 @@ let test_values = {
 | 
			
		||||
      \		['xxx']],
 | 
			
		||||
      \ 'concealcursor': [['', 'n', 'v', 'i', 'c', 'nvic'], ['xxx']],
 | 
			
		||||
      "\ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup',
 | 
			
		||||
      "\ "		'popuphidden', 'noinsert', 'noselect', 'fuzzy', 'menu,longest'],
 | 
			
		||||
      "\ "		'popuphidden', 'noinsert', 'noselect', 'fuzzy', 'preinsert', 'menu,longest'],
 | 
			
		||||
      "\ "		['xxx', 'menu,,,longest,']],
 | 
			
		||||
      \ 'completeitemalign': [['abbr,kind,menu', 'menu,abbr,kind'],
 | 
			
		||||
      \		['', 'xxx', 'abbr', 'abbr,menu', 'abbr,menu,kind,abbr',
 | 
			
		||||
 
 | 
			
		||||
@@ -2964,4 +2964,121 @@ func Test_complete_info_completed()
 | 
			
		||||
  set cot&
 | 
			
		||||
endfunc
 | 
			
		||||
 | 
			
		||||
function Test_completeopt_preinsert()
 | 
			
		||||
  func Omni_test(findstart, base)
 | 
			
		||||
    if a:findstart
 | 
			
		||||
      return col(".")
 | 
			
		||||
    endif
 | 
			
		||||
    return [#{word: "fobar"}, #{word: "foobar"}, #{word: "你的"}, #{word: "你好世界"}]
 | 
			
		||||
  endfunc
 | 
			
		||||
  set omnifunc=Omni_test
 | 
			
		||||
  set completeopt=menu,menuone,preinsert
 | 
			
		||||
 | 
			
		||||
  new
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>f", 'tx')
 | 
			
		||||
  call assert_equal("fobar", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>foo", 'tx')
 | 
			
		||||
  call assert_equal("foobar", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>foo\<BS>\<BS>\<BS>", 'tx')
 | 
			
		||||
  call assert_equal("", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  " delete a character and input new leader
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>foo\<BS>b", 'tx')
 | 
			
		||||
  call assert_equal("fobar", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  " delete preinsert when prepare completion
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>f\<Space>", 'tx')
 | 
			
		||||
  call assert_equal("f ", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>你", 'tx')
 | 
			
		||||
  call assert_equal("你的", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>你好", 'tx')
 | 
			
		||||
  call assert_equal("你好世界", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  call feedkeys("Shello   wo\<Left>\<Left>\<Left>\<C-X>\<C-O>f", 'tx')
 | 
			
		||||
  call assert_equal("hello  fobar wo", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  call feedkeys("Shello   wo\<Left>\<Left>\<Left>\<C-X>\<C-O>f\<BS>", 'tx')
 | 
			
		||||
  call assert_equal("hello   wo", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  call feedkeys("Shello   wo\<Left>\<Left>\<Left>\<C-X>\<C-O>foo", 'tx')
 | 
			
		||||
  call assert_equal("hello  foobar wo", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  call feedkeys("Shello   wo\<Left>\<Left>\<Left>\<C-X>\<C-O>foo\<BS>b", 'tx')
 | 
			
		||||
  call assert_equal("hello  fobar wo", getline('.'))
 | 
			
		||||
  call feedkeys("\<C-E>\<ESC>", 'tx')
 | 
			
		||||
 | 
			
		||||
  " confrim
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>f\<C-Y>", 'tx')
 | 
			
		||||
  call assert_equal("fobar", getline('.'))
 | 
			
		||||
  call assert_equal(5, col('.'))
 | 
			
		||||
 | 
			
		||||
  " cancel
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>fo\<C-E>", 'tx')
 | 
			
		||||
  call assert_equal("fo", getline('.'))
 | 
			
		||||
  call assert_equal(2, col('.'))
 | 
			
		||||
 | 
			
		||||
  call feedkeys("S hello hero\<CR>h\<C-X>\<C-N>", 'tx')
 | 
			
		||||
  call assert_equal("hello", getline('.'))
 | 
			
		||||
  call assert_equal(1, col('.'))
 | 
			
		||||
 | 
			
		||||
  call feedkeys("Sh\<C-X>\<C-N>\<C-Y>", 'tx')
 | 
			
		||||
  call assert_equal("hello", getline('.'))
 | 
			
		||||
  call assert_equal(5, col('.'))
 | 
			
		||||
 | 
			
		||||
  " delete preinsert part
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>fo ", 'tx')
 | 
			
		||||
  call assert_equal("fo ", getline('.'))
 | 
			
		||||
  call assert_equal(3, col('.'))
 | 
			
		||||
 | 
			
		||||
  " whole line
 | 
			
		||||
  call feedkeys("Shello hero\<CR>\<C-X>\<C-L>", 'tx')
 | 
			
		||||
  call assert_equal("hello hero", getline('.'))
 | 
			
		||||
  call assert_equal(1, col('.'))
 | 
			
		||||
 | 
			
		||||
  call feedkeys("Shello hero\<CR>he\<C-X>\<C-L>", 'tx')
 | 
			
		||||
  call assert_equal("hello hero", getline('.'))
 | 
			
		||||
  call assert_equal(2, col('.'))
 | 
			
		||||
 | 
			
		||||
  " can not work with fuzzy
 | 
			
		||||
  set cot+=fuzzy
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>", 'tx')
 | 
			
		||||
  call assert_equal("fobar", getline('.'))
 | 
			
		||||
  call assert_equal(5, col('.'))
 | 
			
		||||
 | 
			
		||||
  " test for fuzzy and noinsert
 | 
			
		||||
  set cot+=noinsert
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>fb", 'tx')
 | 
			
		||||
  call assert_equal("fb", getline('.'))
 | 
			
		||||
  call assert_equal(2, col('.'))
 | 
			
		||||
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>你", 'tx')
 | 
			
		||||
  call assert_equal("你", getline('.'))
 | 
			
		||||
  call assert_equal(1, col('.'))
 | 
			
		||||
 | 
			
		||||
  call feedkeys("S\<C-X>\<C-O>fb\<C-Y>", 'tx')
 | 
			
		||||
  call assert_equal("fobar", getline('.'))
 | 
			
		||||
  call assert_equal(5, col('.'))
 | 
			
		||||
 | 
			
		||||
  bw!
 | 
			
		||||
  bw!
 | 
			
		||||
  set cot&
 | 
			
		||||
  set omnifunc&
 | 
			
		||||
  delfunc Omni_test
 | 
			
		||||
  autocmd! CompleteChanged
 | 
			
		||||
endfunc
 | 
			
		||||
 | 
			
		||||
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user