Mercurial > vim
view runtime/indent/sas.vim @ 34625:ad1b0609b2f8 v9.1.0201
patch 9.1.0201: gM not working correctly with virt text
Commit: https://github.com/vim/vim/commit/366c81a2005370ac738618d889ec0337397a9f96
Author: Dylan Thacker-Smith <dylan.ah.smith@gmail.com>
Date: Sun Mar 24 09:46:56 2024 +0100
patch 9.1.0201: gM not working correctly with virt text
Problem: `gM` would include outer virtual text and its padding when
getting the line length used to calculate the middle of the
line, putting the cursor much closer to virtual text lines.
Solution: Exclude outer virtual text in getting the line length for
`gM`, so that virtual text doesn't influence where the cursor
is moved to (Dylan Thacker-Smith).
closes: #14262
Signed-off-by: Dylan Thacker-Smith <dylan.ah.smith@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 24 Mar 2024 10:00:07 +0100 |
parents | 6dd88e45d47d |
children |
line wrap: on
line source
" Vim indent file " Language: SAS " Maintainer: Zhen-Huan Hu <wildkeny@gmail.com> " Version: 3.0.3 " Last Change: 2022 Apr 06 if exists("b:did_indent") finish endif let b:did_indent = 1 setlocal indentexpr=GetSASIndent() setlocal indentkeys+=;,=~data,=~proc,=~macro let b:undo_indent = "setl inde< indk<" if exists("*GetSASIndent") finish endif let s:cpo_save = &cpo set cpo&vim " Regex that captures the start of a data/proc section let s:section_str = '\v%(^|;)\s*%(data|proc)>' " Regex that captures the end of a run-processing section let s:section_run = '\v%(^|;)\s*run\s*;' " Regex that captures the end of a data/proc section let s:section_end = '\v%(^|;)\s*%(quit|enddata)\s*;' " Regex that captures the start of a control block (anything inside a section) let s:block_str = '\v<%(do>%([^;]+<%(to|over|while)>[^;]+)=|%(compute|define\s+%(column|footer|header|style|table|tagset|crosstabs|statgraph)|edit|layout|method|select)>[^;]+|begingraph)\s*;' " Regex that captures the end of a control block (anything inside a section) let s:block_end = '\v<%(end|endcomp|endlayout|endgraph)\s*;' " Regex that captures the start of a macro let s:macro_str = '\v%(^|;)\s*\%macro>' " Regex that captures the end of a macro let s:macro_end = '\v%(^|;)\s*\%mend\s*;' " Regex that defines the end of the program let s:program_end = '\v%(^|;)\s*endsas\s*;' " List of procs supporting run-processing let s:run_processing_procs = [ \ 'catalog', 'chart', 'datasets', 'document', 'ds2', 'plot', 'sql', \ 'gareabar', 'gbarline', 'gchart', 'gkpi', 'gmap', 'gplot', 'gradar', 'greplay', 'gslide', 'gtile', \ 'anova', 'arima', 'catmod', 'factex', 'glm', 'model', 'optex', 'plan', 'reg', \ 'iml', \ ] " Find the line number of previous keyword defined by the regex function! s:PrevMatch(lnum, regex) let prev_lnum = prevnonblank(a:lnum - 1) while prev_lnum > 0 let prev_line = getline(prev_lnum) if prev_line =~? a:regex break else let prev_lnum = prevnonblank(prev_lnum - 1) endif endwhile return prev_lnum endfunction " Main function function! GetSASIndent() let prev_lnum = prevnonblank(v:lnum - 1) if prev_lnum ==# 0 " Leave the indentation of the first line unchanged return indent(1) else let prev_line = getline(prev_lnum) " Previous non-blank line contains the start of a macro/section/block " while not the end of a macro/section/block (at the same line) if (prev_line =~? s:section_str && prev_line !~? s:section_run && prev_line !~? s:section_end) || \ (prev_line =~? s:block_str && prev_line !~? s:block_end) || \ (prev_line =~? s:macro_str && prev_line !~? s:macro_end) let ind = indent(prev_lnum) + shiftwidth() elseif prev_line =~? s:section_run && prev_line !~? s:section_end let prev_section_str_lnum = s:PrevMatch(v:lnum, s:section_str) let prev_section_end_lnum = max([ \ s:PrevMatch(v:lnum, s:section_end), \ s:PrevMatch(v:lnum, s:macro_end ), \ s:PrevMatch(v:lnum, s:program_end)]) " Check if the section supports run-processing if prev_section_end_lnum < prev_section_str_lnum && \ getline(prev_section_str_lnum) =~? '\v%(^|;)\s*proc\s+%(' . \ join(s:run_processing_procs, '|') . ')>' let ind = indent(prev_lnum) + shiftwidth() else let ind = indent(prev_lnum) endif else let ind = indent(prev_lnum) endif endif " Re-adjustments based on the inputs of the current line let curr_line = getline(v:lnum) if curr_line =~? s:program_end " End of the program " Same indentation as the first non-blank line return indent(nextnonblank(1)) elseif curr_line =~? s:macro_end " Current line is the end of a macro " Match the indentation of the start of the macro return indent(s:PrevMatch(v:lnum, s:macro_str)) elseif curr_line =~? s:block_end && curr_line !~? s:block_str " Re-adjust if current line is the end of a block " while not the beginning of a block (at the same line) " Returning the indent of previous block start directly " would not work due to nesting let ind = ind - shiftwidth() elseif curr_line =~? s:section_str || curr_line =~? s:section_run || curr_line =~? s:section_end " Re-adjust if current line is the start/end of a section " since the end of a section could be inexplicit let prev_section_str_lnum = s:PrevMatch(v:lnum, s:section_str) " Check if the previous section supports run-processing if getline(prev_section_str_lnum) =~? '\v%(^|;)\s*proc\s+%(' . \ join(s:run_processing_procs, '|') . ')>' let prev_section_end_lnum = max([ \ s:PrevMatch(v:lnum, s:section_end), \ s:PrevMatch(v:lnum, s:macro_end ), \ s:PrevMatch(v:lnum, s:program_end)]) else let prev_section_end_lnum = max([ \ s:PrevMatch(v:lnum, s:section_end), \ s:PrevMatch(v:lnum, s:section_run), \ s:PrevMatch(v:lnum, s:macro_end ), \ s:PrevMatch(v:lnum, s:program_end)]) endif if prev_section_end_lnum < prev_section_str_lnum let ind = ind - shiftwidth() endif endif return ind endfunction let &cpo = s:cpo_save unlet s:cpo_save