mirror of
https://github.com/inkarkat/vim-ingo-library.git
synced 2025-12-17 12:00:08 +01:00
202 lines
8.6 KiB
VimL
202 lines
8.6 KiB
VimL
" ingo/regexp.vim: Functions around handling regular expressions.
|
|
"
|
|
" DEPENDENCIES:
|
|
"
|
|
" Copyright: (C) 2010-2016 Ingo Karkat
|
|
" The VIM LICENSE applies to this script; see ':help copyright'.
|
|
"
|
|
" Maintainer: Ingo Karkat <ingo@karkat.de>
|
|
"
|
|
" REVISION DATE REMARKS
|
|
" 1.025.014 28-Apr-2016 Add ingo#regexp#MakeStartWordSearch()
|
|
" ingo#regexp#MakeEndWordSearch() variants of
|
|
" ingo#regexp#MakeWholeWordSearch().
|
|
" 1.023.013 25-Nov-2014 Expose ingo#regexp#MakeWholeWordSearch() (with
|
|
" the second a:pattern argument made optional).
|
|
" 1.020.012 29-May-2014 CHG: At ingo#regexp#FromLiteralText(), add the
|
|
" a:isWholeWordSearch also on either side, or when
|
|
" there are non-keyword characters in the middle
|
|
" of the text. The * command behavior where this
|
|
" is modeled after only handles a smaller subset,
|
|
" and this extension looks sensible and DWIM.
|
|
" 1.013.011 13-Sep-2013 ingo#regexp#FromWildcard(): Limit * glob
|
|
" matching to individual path components and add
|
|
" ** for cross-directory matching.
|
|
" 1.011.010 24-Jul-2013 Minor: Remove invalid "e" flag from
|
|
" substitute().
|
|
" 1.006.009 24-May-2013 Move into ingo-library.
|
|
" Restructure ingo#regexp#FromLiteralText() a bit.
|
|
" 008 21-Feb-2013 Move ingocollections.vim to ingo-library.
|
|
" 007 03-Sep-2011 Extend ingosearch#GetLastForwardSearchPattern()
|
|
" to take optional count into search history.
|
|
" 006 02-Sep-2011 Add ingosearch#GetLastForwardSearchPattern().
|
|
" 005 10-Jun-2011 Add ingosearch#NormalizeMagicness().
|
|
" 004 17-May-2011 Make ingosearch#EscapeText() public.
|
|
" Extract ingosearch#GetSpecialSearchCharacters()
|
|
" from s:specialSearchCharacters and expose it.
|
|
" 003 12-Feb-2010 Added ingosearch#WildcardExprToSearchPattern()
|
|
" from the :Help command in ingocommands.vim.
|
|
" 002 05-Jan-2010 BUG: Wrong escaping with 'nomagic' setting.
|
|
" Corrected s:specialSearchCharacters for that
|
|
" case.
|
|
" Renamed ingosearch#GetSearchPattern() to
|
|
" ingosearch#LiteralTextToSearchPattern().
|
|
" 001 05-Jan-2010 file creation with content from
|
|
" SearchHighlighting.vim.
|
|
|
|
function! ingo#regexp#GetSpecialCharacters()
|
|
" The set of characters that must be escaped depends on the 'magic' setting.
|
|
return ['^$', '^$.*[~'][&magic]
|
|
endfunction
|
|
function! ingo#regexp#EscapeLiteralText( text, additionalEscapeCharacters )
|
|
"*******************************************************************************
|
|
"* PURPOSE:
|
|
" Escape the literal a:text for use in search command.
|
|
" The ignorant approach is to use atom \V, which sets the following pattern to
|
|
" "very nomagic", i.e. only the backslash has special meaning. For \V, \ still
|
|
" must be escaped. But that's not how the built-in star command works.
|
|
" Instead, all special search characters must be escaped.
|
|
"
|
|
" This works well even with <Tab> (no need to change ^I into \t), but not with
|
|
" a line break, which must be changed from ^M to \n.
|
|
"
|
|
" We also may need to escape additional characters like '/' or '?', because
|
|
" that's done in a search via '*', '/' or '?', too. As the character depends
|
|
" on the search direction ('/' vs. '?'), this is passed in as
|
|
" a:additionalEscapeCharacters.
|
|
"
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:text Literal text.
|
|
" a:additionalEscapeCharacters For use in the / command, add '/', for the
|
|
" backward search command ?, add '?'. For
|
|
" assignment to @/, always add '/', regardless
|
|
" of the search direction; this is how Vim
|
|
" escapes it, too. For use in search(), pass
|
|
" nothing.
|
|
"* RETURN VALUES:
|
|
" Regular expression for matching a:text.
|
|
"*******************************************************************************
|
|
return substitute(escape(a:text, '\' . ingo#regexp#GetSpecialCharacters() . a:additionalEscapeCharacters), "\n", '\\n', 'g')
|
|
endfunction
|
|
|
|
function! ingo#regexp#MakeWholeWordSearch( text, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Generate a pattern that searches only for whole words of a:text, but only if
|
|
" a:text actually starts / ends with keyword characters (so that non-word
|
|
" a:text still matches (anywhere)).
|
|
" The star command only creates a \<whole word\> search pattern if the <cword>
|
|
" actually only consists of keyword characters. Since
|
|
" ingo#regexp#FromLiteralText() could handle a superset (e.g. also
|
|
" "foo...bar"), just ensure that the keyword boundaries can be enforced at
|
|
" either side, to avoid enclosing a non-keyword side and making a match
|
|
" impossible with it (e.g. "\<..bar\>").
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:text Text / pattern to be searched for. Note that this isn't escaped in any form;
|
|
" you probably want to escape backslashes beforehand and use \V "very
|
|
" nomagic" on the result.
|
|
" a:pattern If passed, this is adapted according to what a:text is about.
|
|
" Useful if the pattern has already been so warped (e.g. by
|
|
" enclosing in /\(...\|...\)/) that word boundary detection on the
|
|
" original text wouldn't work.
|
|
"* RETURN VALUES:
|
|
" a:text / a:pattern, with additional \< / \> atoms if applicable.
|
|
"******************************************************************************
|
|
let l:pattern = (a:0 ? a:1 : a:text)
|
|
if a:text =~# '^\k'
|
|
let l:pattern = '\<' . l:pattern
|
|
endif
|
|
if a:text =~# '\k$'
|
|
let l:pattern .= '\>'
|
|
endif
|
|
return l:pattern
|
|
endfunction
|
|
function! ingo#regexp#MakeStartWordSearch( text, ... )
|
|
let l:pattern = (a:0 ? a:1 : a:text)
|
|
if a:text =~# '^\k'
|
|
let l:pattern = '\<' . l:pattern
|
|
endif
|
|
return l:pattern
|
|
endfunction
|
|
function! ingo#regexp#MakeEndWordSearch( text, ... )
|
|
let l:pattern = (a:0 ? a:1 : a:text)
|
|
if a:text =~# '\k$'
|
|
let l:pattern .= '\>'
|
|
endif
|
|
return l:pattern
|
|
endfunction
|
|
function! ingo#regexp#FromLiteralText( text, isWholeWordSearch, additionalEscapeCharacters )
|
|
"*******************************************************************************
|
|
"* PURPOSE:
|
|
" Convert literal a:text into a regular expression, similar to what the
|
|
" built-in * command does.
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:text Literal text.
|
|
" a:isWholeWordSearch Flag whether only whole words (* command) or any
|
|
" contained text (g* command) should match.
|
|
" Note: If you do not need the a:isWholeWordSearch flag,
|
|
" you can also use the ingo#regexp#EscapeLiteralText()
|
|
" function.
|
|
" a:additionalEscapeCharacters For use in the / command, add '/', for the
|
|
" backward search command ?, add '?'. For
|
|
" assignment to @/, always add '/', regardless
|
|
" of the search direction; this is how Vim
|
|
" escapes it, too. For use in search(), pass
|
|
" nothing.
|
|
"* RETURN VALUES:
|
|
" Regular expression for matching a:text.
|
|
"*******************************************************************************
|
|
if a:isWholeWordSearch
|
|
return ingo#regexp#MakeWholeWordSearch(a:text, ingo#regexp#EscapeLiteralText(a:text, a:additionalEscapeCharacters))
|
|
else
|
|
return ingo#regexp#EscapeLiteralText(a:text, a:additionalEscapeCharacters)
|
|
endif
|
|
endfunction
|
|
|
|
function! ingo#regexp#FromWildcard( wildcardExpr, additionalEscapeCharacters )
|
|
"*******************************************************************************
|
|
"* PURPOSE:
|
|
" Convert a shell-like a:wildcardExpr which may contain wildcards ? and * into
|
|
" an (unanchored!) regular expression.
|
|
"
|
|
" The ingo#regexp#fromwildcard#Convert() supports the full range of wildcards
|
|
" and considers the path separators on different platforms. An anchored
|
|
" version is ingo#regexp#fromwildcard#AnchoredToPathBoundaries().
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:wildcardExpr Text containing file wildcards.
|
|
" a:additionalEscapeCharacters For use in the / command, add '/', for the
|
|
" backward search command ?, add '?'. For
|
|
" assignment to @/, always add '/', regardless
|
|
" of the search direction; this is how Vim
|
|
" escapes it, too. For use in search(), pass
|
|
" nothing.
|
|
"* RETURN VALUES:
|
|
" Regular expression for matching a:wildcardExpr.
|
|
"*******************************************************************************
|
|
let l:expr = '\V' . escape(a:wildcardExpr, '\' . a:additionalEscapeCharacters)
|
|
|
|
" From the wildcards; emulate ?, * and **, but not [xyz].
|
|
let l:expr = substitute(l:expr, '?', '\\.', 'g')
|
|
let l:expr = substitute(l:expr, '\*\*', '\\.\\*', 'g')
|
|
let l:expr = substitute(l:expr, '\*', '\\[^/\\\\]\\*', 'g')
|
|
return l:expr
|
|
endfunction
|
|
|
|
" vim: set ts=8 sts=4 sw=4 noexpandtab ff=unix fdm=syntax :
|