├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── tests.yml ├── .gitignore ├── .rspec ├── .travis.yml ├── Flavorfile ├── Gemfile ├── License.md ├── README.md ├── Rakefile ├── addon-info.json ├── after └── ftplugin │ ├── c │ └── c_brackets.vim │ ├── help_brackets.vim │ ├── html │ └── html_brackets.vim │ ├── javascript_brackets.vim │ ├── markdown_brackets.vim │ ├── perl │ └── perl_brackets.vim │ ├── ruby │ └── ruby_brackets.vim │ ├── tex │ └── tex_brackets.vim │ └── vim │ └── vim_brackets.vim ├── autoload └── lh │ ├── brackets.vim │ ├── cpp │ └── brackets.vim │ ├── html │ └── brackets.vim │ ├── map.vim │ ├── markdown │ └── brackets.vim │ ├── marker.vim │ └── vim │ └── brackets.vim ├── doc ├── default_brackets.md └── lh-map-tools.txt ├── ftplugin └── python │ └── python_snippets.vim ├── mkVba └── mk-lh-map-tools.vim ├── plugin ├── bracketing.base.vim ├── common_brackets.vim └── misc_map.vim ├── spec ├── c_spec.rb ├── cpp_spec.rb ├── lh-brackets.vim_spec.rb ├── python_spec.rb ├── spec_helper.rb ├── support │ ├── c-snippets.vim │ ├── test.vimrc │ └── vim-snippets.vim ├── tex_spec.rb └── vim_spec.rb └── tests ├── Flavorfile └── lh ├── html-brackets.vim ├── test-functions.vim ├── test-split.vim └── vim-brackets.vim /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | labels: bug 5 | 6 | --- 7 | 8 | **Describe the bug** 9 | A clear and concise description of what the bug is. 10 | 11 | **To Reproduce** 12 | Steps to reproduce the behavior: 13 | 1. Go to '...' 14 | 2. Click on '....' 15 | 3. Scroll down to '....' 16 | 4. See error 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If pertinent, add screenshots to help explain your problem. 23 | 24 | ** Context (please complete the following information):** 25 | - Vim version [e.g. 8.0.1157] 26 | - Other plugins installed 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] ; I'd like to be able to [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake 6 | # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby 7 | 8 | name: CI 9 | 10 | on: 11 | push: 12 | branches: [ "master" ] 13 | pull_request: 14 | branches: [ "master" ] 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | test: 21 | name: "test on ${{ matrix.os }} ; ${{ matrix.neovim && 'neovim' || 'vim' }}" 22 | 23 | strategy: 24 | matrix: 25 | # Testing doesn't seem to work on Windows: output log file 26 | # cannot be read... 27 | # os: [ubuntu-latest, macos-latest, windows-latest] 28 | os: [ubuntu-latest, macos-latest] 29 | neovim: [false] 30 | # neovim: [false, true] 31 | # TODO: Test different flavours of Vim... 32 | 33 | runs-on: ${{ matrix.os }} 34 | 35 | steps: 36 | - uses: actions/checkout@v4 37 | - name: Set up Ruby 38 | uses: ruby/setup-ruby@v1 39 | with: 40 | ruby-version: 3.0 41 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 42 | - name: Setup Vim 43 | uses: rhysd/action-setup-vim@v1 44 | # uses: thinca/action-setup-vim@v2 45 | id: vim 46 | with: 47 | neovim: ${{matrix.neovim }} 48 | configure-args: | 49 | --with-features=huge 50 | 51 | - name: Run tests on Linux 52 | if: runner.os == 'Linux' # headless execution is required on Linux 53 | run: | 54 | bundle list 55 | xvfb-run bundle exec rake ci 56 | - name: Run tests on ${{ matrix.os }} 57 | if: runner.os != 'Linux' 58 | run: | 59 | bundle exec rake ci 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | *.sw* 3 | *~ 4 | *.pyc 5 | tests/lh/*.log 6 | *.lock 7 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | -I ~/.vim-flavor/repos/LucHermitte_vim-UT/spec 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: ruby 3 | cache: bundler 4 | rvm: 5 | - 2.5.3 6 | script: bundle exec rake ci 7 | addons: 8 | apt: 9 | packages: 10 | - vim-gtk 11 | services: 12 | - xvfb 13 | -------------------------------------------------------------------------------- /Flavorfile: -------------------------------------------------------------------------------- 1 | flavor 'LucHermitte/lh-vim-lib', '>= 5.3.0' 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rspec', '~> 3.13.0' 4 | gem 'vimrunner', '~> 0.3.5' 5 | gem 'rake', '~> 13.0.1' 6 | gem 'vim-flavor', '~> 4.0.3' 7 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | Copyright 2001-2015, Luc Hermitte 2 | 3 | # Scripts License 4 | 5 | All scripts (VimL, templates, bash, perl, etc.) from lh-vim are 6 | distributed under FSF's GPLv3 license. 7 | 8 | See http://www.gnu.org/licenses/gpl.txt for more information. 9 | 10 | 11 | # License exception for generated code 12 | 13 | Many lh-vim scripts generate code. Unless specified otherwise, the code generated is under the following license exception. 14 | 15 | 16 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 17 | 18 | This Exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). It applies to a given file that bears a notice placed by the copyright holder of the file stating that the file is governed by GPLv3 along with this Exception. 19 | 20 | The purpose of this Exception is to allow distribution of lh-vim's typical output under terms of the recipient's choice (including proprietary). 21 | 22 | ## 0. Definitions. 23 | "Covered Code" is the source or object code of a version of lh-vim that is a covered work under this License. 24 | 25 | "Normally Copied Code" for a version of lh-vim means all parts of its Covered Code which that version can copy from its code (i.e., not from its input file) into its minimally verbose, non-debugging and non-tracing output. 26 | 27 | "Ineligible Code" is Covered Code that is not Normally Copied Code. 28 | 29 | ## 1. Grant of Additional Permission. 30 | You have permission to propagate output of lh-vim, even if such propagation would otherwise violate the terms of GPLv3. However, if by modifying lh-vim you cause any Ineligible Code of the version you received to become Normally Copied Code of your modified version, then you void this Exception for the resulting covered work. If you convey that resulting covered work, you must remove this Exception in accordance with the second paragraph of Section 7 of GPLv3. 31 | 32 | ## 2. No Weakening of lh-vim Copyleft. 33 | 34 | The availability of this Exception does not imply any general presumption that third-party software is unaffected by the copyleft requirements of the license of lh-vim. 35 | 36 | Disclaimer: This lh-vim license exception is directly derived from [AUTOCONF CONFIGURE SCRIPT EXCEPTION](http://www.gnu.org/licenses/autoconf-exception.html) to GPLv3 license. 37 | 38 | # License for documentation 39 | 40 | The documentation of lh-vim scripts distributed along the scripts, and of the wiki pages here are under the Creative Commons license ([CC by SA 3.0](http://creativecommons.org/licenses/by-sa/3.0/)) 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lh-brackets [![Last release][Releases-badge]][Releases-url] [![Build Status][gh-action-badge]][gh-action-result] [![Project Stats][openhub-badge]][openhub-url] 2 | 3 | [Releases-badge]: https://img.shields.io/github/tag/LucHermitte/lh-brackets.svg 4 | [Releases-url]: https://github.com/LucHermitte/lh-brackets/tags 5 | [gh-action-badge]: ./../../actions/workflows/tests.yml/badge.svg?branch=master "Test" 6 | [gh-action-result]: ./../../actions/workflows/tests.yml?query=branch%3Amaster 7 | [openhub-badge]: https://www.openhub.net/p/21020/widgets/project_thin_badge.gif 8 | [openhub-url]: https://www.openhub.net/p/21020 9 | 10 | ## Features 11 | 12 | lh-brackets (ex- map-tool) provides various commands and functions to help design smart and advanced mappings dedicated to text insertion. 13 | 14 | It is made of three sub-systems: 15 | * [the core bracketing-system](#the-bracketing-subsystem), 16 | * [a placeholder subsystem](#the-placeholder-subsystem), 17 | * [various Vim functions to support ftplugin definitions](#the-vim-library). 18 | 19 | ### The bracketing subsystem 20 | 21 | #### Brackets insertion 22 | 23 | This subsystem provides a command that helps define INSERT-, NORMAL-, and VISUAL-mode mappings to insert any pairs of brackets-like characters. 24 | 25 | * The INSERT-mode mappings will 26 | * insert the pair of brackets-like characters when the opening one is triggered, add a placeholder after the closing character, and move the cursor between the two bracket characters; 27 | * insert the closing character when pressed, or move after it if it is the next character after the cursor ; 28 | * delete the current pair of empty brackets when `` is hit from within the brackets (following placeholders will also be deleted) (this can be disabled by setting `[gb]:cb_delete_empty_brackets` to 0) 29 | * insert an extra newline when `` is hit within an empty pair of curly-brackets {} (this can be disabled by setting `[gb]:cb_newline_within_empty_brackets` to 0) 30 | * The VISUAL-mode mapping will surround the current selection with the pair of bracket-like characters ; 31 | * The NORMAL-mode mapping will select the current word (or the current line depending on the use of the newline (`-nl`) option), and then surround this selection with the pair of bracket-like characters. 32 | 33 | It is possible to: 34 | * tune what is exactly inserted in INSERT-mode (thanks to the `-open` and `-close` options), 35 | * not insert the placeholder (depending on `b:usemark` value), 36 | * specify which keys sequence actually triggers the mappings defined (thanks to the `-trigger` option), 37 | * define the mappings only in some modes (thanks to the options `-insert`, `-visual`, and also `-normal`) 38 | * make the mappings line-wise (thanks to the `-nl` option), 39 | * tune how the NORMAL-mode mapping select a current _anything_ (thanks to the `-normal` option), 40 | * toggle the definitions of all the brackets mappings by pressing `` (`:h ToggleBrackets`) ; 41 | * make the mappings global with `:Brackets!`, or local to a buffer with `:Brackets`. ; 42 | * neutralize the INSERT-mode mappings: 43 | * for specific filetypes with `-but` option 44 | * when the cursor is not under a space, coma, (semi-)colon, a equal sign, a 45 | closing pair character or at the end of line by default -- it will be 46 | possible to tune this feature in a later version 47 | * specify exactly which is the canonical pair for deletion when it's not immediate from the context (thanks to the `-pair` option) 48 | 49 | 50 | Here is an excerpt from the C&C++ brackets definitions, see the documentation for more help. 51 | ``` 52 | let b:usemarks = 1 53 | let b:cb_jump_on_close = 1 54 | 55 | :Brackets { } -visual=0 -nl 56 | :Brackets { } -visual=0 -trigger=#{ 57 | :Brackets { } -visual=1 -insert=0 -nl -trigger={ 58 | :Brackets { } -visual=1 -insert=0 59 | 60 | :Brackets ( ) 61 | :Brackets [ ] -visual=0 62 | :Brackets [ ] -insert=0 -trigger=[ 63 | :Brackets " " -visual=0 -insert=1 -escapable 64 | :Brackets " " -visual=1 -insert=0 -trigger="" 65 | :Brackets ' ' -visual=0 -insert=1 66 | :Brackets ' ' -visual=1 -insert=0 -trigger='' 67 | :Brackets < > -open=function('lh#cpp#brackets#lt') -visual=0 68 | ``` 69 | 70 | **Note:** This feature has been completely rewritten for the version 1.0.0 of map-tools. The old way of tuning the brackets insertion is no longer available. 71 | 72 | By default, the [mappings are active for most filetypes](doc/default_brackets.md). 73 | 74 | #### Brackets replacement 75 | 76 | lh-brackets provides mappings (originally from auctex.vim) to replace a pair of bracket-characters by another pair of bracket-characters. See `:h brackets_manipulations` for more information. 77 | 78 | 79 | ### The placeholder subsystem 80 | 81 | This subsystem provides functions and mappings to: 82 | * mark places in the code where we could jump to later, 83 | See the help about `!mark!`, `lh#marker#txt()`, and `MarkersMark` 84 | * jump forward and backward to those places. 85 | See the help about `!jump!`, and `MarkersJumpF` 86 | * close all placeholders on the same line that are after closing bracket-like 87 | characters and jump to the last one -- see 88 | `MarkersCloseAllAndJumpToLast` which is binded by default to `` (or `$` in terminal instancef of Vim). 89 | 90 | The marker/placeholder characters: 91 | * default to the French quote characters («»), 92 | * can be specified on a filetype basis, 93 | * are converted to match the current encoding, 94 | * can be shared with the ones from imaps.vim (`:h g:use_place_holders`). 95 | 96 | Jumping to the next/previous placeholder: 97 | * is binded to `` (GUI) or `` (terminal) by default (see `:h MarkersJumpF`), or ``/`` to jump backward. Can be disabled by setting `g:marker_define_jump_mappings` to 0. 98 | * can be tuned to delete or select the placeholder the cursor is jumping to (`:h g:marker_prefers_select`, `:h g:marker_select_empty_marks`), 99 | * can select or ignore the placeholder where the cursor is currently within (if any) (`:h g:marker_select_current`, `:h g:marker_select_current_fwd`), 100 | * may move the line of the placeholder (we jump to) to the middle of the window (`:h g:marker_center`), 101 | * respects `'wrapscan'`, 102 | * opens the folder where the placeholder, we jump to, is, 103 | * doesn't break _redo_ (is the case of empty placeholders, when placeholders 104 | are deleted instead of selected) ; this feature requires Vim 7.4-849. 105 | 106 | 107 | ### The Vim library 108 | 109 | As [lh-vim-lib](http://github.com/LucHermitte/lh-vim-lib), map-tools provides a few functions of its own. All these functions are specialized into the definition of smart abbreviations and INSERT-mode mappings. 110 | 111 | | Function | Purpose | 112 | |:----------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------| 113 | | `lh#map#no_context()`, `lh#map#no_context2()` | Core functions to define mappings that only expand outside of _string_, _comment_, and _character_ contexts | 114 | | `lh#map#4_these_contexts()` | Like `lh#map#no_context()`, except this time we can specify which text must be returned depending on the current context | 115 | | `lh#map#insert_around_visual()` | This is the core surrounding function ; the surrounding text is not interpreted | 116 | | `lh#map#surround()` | Interprets the `!.*!` mappings that are passed to `lh#map#insert_around_visual()` (`!cursorhere!` tells were to put the cursor). This function also recognises when the selected area is actually a marker/placeholder in order to not surround, but expand instead. | 117 | | `lh#map#build_map_seq()` | Core function that interprets `!.*!` mappings | 118 | | `lh#map#eat_char()`, `:I(nore)abbr` | Permits to define abbreviations that do not insert a whitespace when the `` key is used to trigger the abbreviation | 119 | | `lh#map#insert_seq()` | High level function that interprets `!.*!` mappings, and take the context into account | 120 | 121 | # Installation 122 | * Requirements: Vim 7.+ (7.4-849 in order to support redo), [lh-vim-lib](http://github.com/LucHermitte/lh-vim-lib) v5.3.0+, [lh-style](http://github.com/LucHermitte/lh-style) v1.0.0+ for unit testing. 123 | * With [vim-addon-manager](https://github.com/MarcWeber/vim-addon-manager), install lh-brackets (this is the preferred method because of the dependencies) 124 | 125 | ```vim 126 | ActivateAddons lh-brackets 127 | ``` 128 | 129 | * or with [vim-flavor](https://github.com/kana/vim-flavor) (which also support dependencies) 130 | 131 | ``` 132 | flavor 'LucHermitte/lh-brackets' 133 | ``` 134 | 135 | * or you can clone the git repositories 136 | 137 | ```bash 138 | git clone git@github.com:LucHermitte/lh-vim-lib.git 139 | git clone git@github.com:LucHermitte/lh-brackets.git 140 | ``` 141 | 142 | * or with Vundle/NeoBundle: 143 | 144 | ```vim 145 | Bundle 'LucHermitte/lh-vim-lib' 146 | Bundle 'LucHermitte/lh-brackets' 147 | ``` 148 | 149 | ## Credits 150 | * This bracketing system is actually a variation on [Stephen Riehm's original bracketing system](http://mywebpage.netscape.com/bbenjif/vim/Riehm/doc/) ; 151 | * The brackets manipulation comes from Saul Lubkin code, also present in [auctex.vim](http://www.vim.org/scripts/script.php?script_id=162) ; 152 | * Using SELECT-mode when reaching a placeholder was a suggestion from Gergely Kontra. 153 | 154 | ## See also 155 | * [imaps.vim, from LaTeX-suite](http://www.vim.org/scripts/script.php?script_id=475), with which map-tools is compatible (there is no conflictual mappings if both are installed) ; 156 | * All the [brackets related tips on vim.wikia](http://vim.wikia.com/wiki/Category:Brackets) ; 157 | * Most of my ftplugins for examples of use, or more simply the [Python ftplugin](ftplugin/python/python_snippets.vim) shipped with lh-brackets. 158 | * [muTemplate](http://github.com/LucHermitte/mu-template), a template-files expander built on top of map-tools. 159 | * [surround plugin on SF](http://www.vim.org/scripts/script.php?script_id=1697) 160 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | require 'rspec/core/rake_task' 4 | 5 | RSpec::Core::RakeTask.new(:spec) 6 | 7 | task :ci => [:dump, :install, :test] 8 | 9 | task :default => :spec 10 | 11 | task :dump do 12 | sh 'vim --version' 13 | end 14 | 15 | task :test => :spec 16 | 17 | task :spec do 18 | # 'spec' is implicitly run as well 19 | # sh 'rspec --require spec_helper' 20 | sh "bundle exec rspec ~/.vim-flavor/repos/LucHermitte_vim-UT/spec/UT_spec_v2.rb" 21 | end 22 | 23 | task :install do 24 | sh 'cat Flavorfile >> tests/Flavorfile' 25 | sh 'cd tests && bundle exec vim-flavor install' 26 | end 27 | -------------------------------------------------------------------------------- /addon-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "lh-brackets", 3 | "version" : "dev", 4 | "author" : "Luc Hermitte ", 5 | "maintainer" : "Luc Hermitte ", 6 | "repository" : {"type": "git", "url": "git@github.com:LucHermitte/lh-brackets.git"}, 7 | "dependencies" : { 8 | "lh-vim-lib" : {"type" : "git", "url" : "git@github.com:LucHermitte/lh-vim-lib.git"}, 9 | }, 10 | "description" : "LH' bracketing system", 11 | "homepage" : "http://github.com/LucHermitte/lh-brackets" 12 | } 13 | -------------------------------------------------------------------------------- /after/ftplugin/c/c_brackets.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/lh-brackets/40af9b67424003a03e8384eab81256bfe535db0b/after/ftplugin/c/c_brackets.vim -------------------------------------------------------------------------------- /after/ftplugin/help_brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: ftplugin/help.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 3.5.4 6 | let s:k_version = 354 7 | " Created: 14th Dec 2015 8 | " Last Update: 30th Apr 2019 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Mappings to insert help pairs 12 | " - | -> || 13 | " - ` -> `` 14 | " - * -> ** in INSERT-MODE, 15 | " - * in VISUAL and NORMAL modes 16 | " 17 | "------------------------------------------------------------------------ 18 | " History: «history» 19 | " TODO: «missing features» 20 | " }}}1 21 | "============================================================================= 22 | 23 | " Buffer-local Definitions {{{1 24 | " Avoid local reinclusion {{{2 25 | if &cp || (exists("b:loaded_ftplug_help_brackets") 26 | \ && (b:loaded_ftplug_help_brackets >= s:k_version) 27 | \ && !exists('g:force_reload_ftplug_help_brackets')) 28 | finish 29 | endif 30 | let b:loaded_ftplug_help_brackets = s:k_version 31 | let s:cpo_save=&cpo 32 | set cpo&vim 33 | " Avoid local reinclusion }}}2 34 | 35 | "------------------------------------------------------------------------ 36 | " Brackets & all {{{2 37 | " ------------------------------------------------------------------------ 38 | if ! lh#option#get('cb_no_default_brackets', 0) 39 | let b:cb_jump_on_close = 1 40 | 41 | :Brackets * * -default -visual=0 42 | :Brackets * * -default -insert=0 -trigger=* 43 | :Brackets ` ` -default 44 | :Brackets | | -default 45 | endif 46 | 47 | " }}}1 48 | "------------------------------------------------------------------------ 49 | let &cpo=s:cpo_save 50 | "============================================================================= 51 | " vim600: set fdm=marker: 52 | -------------------------------------------------------------------------------- /after/ftplugin/html/html_brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: ftplugin/html/html_brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.5.4 8 | " Created: 24th Mar 2008 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " html-ftplugin that defines the default preferences regarding the 12 | " bracketing mappings we want to use. 13 | " 14 | "------------------------------------------------------------------------ 15 | " Note: 16 | " In order to override these default definitions, copy this file into a 17 | " directory that comes before the {rtp}/after/ftplugin/html/ you choosed -- 18 | " typically $HOME/.vim/ftplugin/html/ (:h 'rtp'). 19 | " Then, replace the calls to :Brackets, without the `-default` flag 20 | " 21 | " TODO: 22 | " }}}1 23 | "============================================================================= 24 | 25 | " Buffer-local Definitions {{{1 26 | " Avoid local reinclusion {{{2 27 | if &ft == 'markdown' 28 | " We don't want these mappings in markdown 29 | finish 30 | endif 31 | 32 | if exists("b:loaded_ftplug_html_brackets") && !exists('g:force_reload_ftplug_html_brackets') 33 | finish 34 | endif 35 | let s:cpo_save=&cpo 36 | set cpo&vim 37 | let b:loaded_ftplug_html_brackets = 354 38 | " Avoid local reinclusion }}}2 39 | 40 | "------------------------------------------------------------------------ 41 | " Brackets & all {{{2 42 | " It seems that function() does not load anything with some versions of vim 43 | if !exists('lh#html#brackets#lt') 44 | runtime autoload/lh/html/brackets.vim 45 | endif 46 | 47 | let b:cb_jump_on_close = 1 48 | 49 | if ! lh#option#get('cb_no_default_brackets', 0) 50 | Brackets < > -default 51 | \ -visual=0 52 | \ -open=function('lh#html#brackets#lt') 53 | \ -clos=function('lh#html#brackets#gt') 54 | Brackets < > -default -visual=1 -insert=0 -trigger=< 55 | endif 56 | 57 | " }}}1 58 | "------------------------------------------------------------------------ 59 | let &cpo=s:cpo_save 60 | "============================================================================= 61 | " vim600: set fdm=marker: 62 | -------------------------------------------------------------------------------- /after/ftplugin/javascript_brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: ftplugin/js/js_brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.5.4 8 | " Created: 26th May 2004 9 | " Last Update: 30th Apr 2019 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " js-ftplugin that defines the default preferences regarding the 13 | " bracketing mappings we want to use. 14 | " 15 | "------------------------------------------------------------------------ 16 | " Note: 17 | " In order to override these default definitions, copy this file into a 18 | " directory that comes before the {rtp}/after/ftplugin/javascript/ you 19 | " choosed -- typically $HOME/.vim/ftplugin/javascript/ (:h 'rtp'). 20 | " Then, replace the calls to :Brackets, without the `-default` flag 21 | " 22 | " History: 23 | " v2.0.0 GPLv3 24 | " v1.0.0 28th Jul 2009 25 | " Adapted from ftplugin/c/c_brackets.vim 26 | " TODO: 27 | " }}}1 28 | "============================================================================= 29 | 30 | 31 | "============================================================================= 32 | " Avoid buffer reinclusion {{{1 33 | if exists('b:loaded_ftplug_javascript_brackets') && !exists('g:force_reload_ftplug_javascript_brackets') 34 | finish 35 | endif 36 | let b:loaded_ftplug_js_brackets = 354 37 | 38 | let s:cpo_save=&cpo 39 | set cpo&vim 40 | " }}}1 41 | "------------------------------------------------------------------------ 42 | " Brackets & all {{{1 43 | " ------------------------------------------------------------------------ 44 | if ! lh#option#get('cb_no_default_brackets', 0) 45 | let b:cb_jump_on_close = 1 46 | " Use the default definitions from plugin/common_brackets.vim 47 | 48 | " :Brackets /* */ -default -visual=0 49 | " :Brackets /** */ -default -visual=0 -trigger=/! 50 | " 51 | :Brackets { } -default -visual=1 -insert=0 -nl -trigger={ 52 | " } 53 | endif 54 | 55 | " }}}1 56 | "============================================================================= 57 | let &cpo=s:cpo_save 58 | "============================================================================= 59 | " vim600: set fdm=marker: 60 | -------------------------------------------------------------------------------- /after/ftplugin/markdown_brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: ftplugin/markdown-brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | let s:k_version = 360 9 | " Created: 13th Mar 2014 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " Mapping to insert markdown pairs: 13 | " - * -> ** ; twice for **** ; 14 | " * for surrounding 15 | " - _ -> __ ; twice for ____ 16 | " - ` -> `` 17 | " - ~ -> ; ~ for surrounding 18 | " - -> delete empty pair 19 | " 20 | " }}}1 21 | "============================================================================= 22 | 23 | " Avoid local reinclusion {{{1 24 | if &cp || (exists("b:loaded_ftplug_markdown_brackets") 25 | \ && (b:loaded_ftplug_markdown_brackets >= s:k_version) 26 | \ && !exists('g:force_reload_ftplug_markdown_brackets')) 27 | finish 28 | endif 29 | let b:loaded_ftplug_markdown_brackets = s:k_version 30 | let s:cpo_save=&cpo 31 | set cpo&vim 32 | " Avoid local reinclusion }}}1 33 | 34 | "------------------------------------------------------------------------ 35 | " Brackets & all {{{1 36 | " ------------------------------------------------------------------------ 37 | if ! lh#option#get('cb_no_default_brackets', 0) 38 | let b:cb_jump_on_close = 1 39 | " Use the default definitions from plugin/common_brackets.vim 40 | 41 | " :Brackets /* */ -default -visual=0 42 | " :Brackets /** */ -default -visual=0 -trigger=/! 43 | " 44 | :Brackets _ _ -default -open=function('lh#markdown#brackets#underscore') 45 | :Brackets * * -default -open=function('lh#markdown#brackets#star') -visual=0 46 | :Brackets * * -default -insert=0 -trigger=* 47 | " :Brackets * * -default -open=function('lh#markdown#brackets#star') -close=function('lh#markdown#brackets#star') 48 | :Brackets ` ` -default -open=function('lh#markdown#brackets#backtick') 49 | :Brackets <\del> -default -trigger=~ -insert=0 50 | :Brackets ~ ~ -default -open=function('lh#markdown#brackets#strike') -visual=0 -pair=,, 51 | " 52 | " Todo: add 53 | " * remove the second '*' 54 | " ** -> '****' 55 | 56 | call lh#brackets#define_imap('$', 57 | \ [{'condition': "getline('.')[col('.')-2:] =~ '^`\\$'", 58 | \ 'action': 'lh#markdown#brackets#close_math()'}], 59 | \ 1, '$') 60 | endif 61 | 62 | " }}}1 63 | "------------------------------------------------------------------------ 64 | let &cpo=s:cpo_save 65 | "============================================================================= 66 | " vim600: set fdm=marker: 67 | -------------------------------------------------------------------------------- /after/ftplugin/perl/perl_brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: ftplugin/perl/perl_brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.5.4 8 | " Created: 26th May 2004 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " perl-ftplugin that defines the default preferences regarding the 12 | " bracketing mappings we want to use. 13 | " 14 | "------------------------------------------------------------------------ 15 | " Note: 16 | " In order to override these default definitions, copy this file into a 17 | " directory that comes before the {rtp}/after/ftplugin/perl/ you choosed -- 18 | " typically $HOME/.vim/ftplugin/perl/ (:h 'rtp'). 19 | " Then, replace the calls to :Brackets, without the `-default` flag 20 | " 21 | " History: 22 | " v1.0.0 07th Sep 2009 23 | " copy-paste of c_brackets.vim 24 | " v2.0.0 GPLv3 25 | " TODO: 26 | " }}}1 27 | "============================================================================= 28 | 29 | 30 | "============================================================================= 31 | " Avoid buffer reinclusion {{{1 32 | if exists('b:loaded_ftplug_perl_brackets') && !exists('g:force_reload_ftplug_perl_brackets') 33 | finish 34 | endif 35 | let b:loaded_ftplug_perl_brackets = 353 36 | 37 | let s:cpo_save=&cpo 38 | set cpo&vim 39 | " }}}1 40 | "------------------------------------------------------------------------ 41 | " Brackets & all {{{1 42 | " ------------------------------------------------------------------------ 43 | if ! lh#option#get('cb_no_default_brackets', 0) 44 | let b:cb_jump_on_close = 1 45 | " Use the default definitions from plugin/common_brackets.vim 46 | :Brackets < > -default -visual=1 -insert=0 -trigger=< 47 | :Brackets { } -default -visual=1 -insert=0 -nl -trigger={ 48 | " } 49 | endif 50 | 51 | " }}}1 52 | "============================================================================= 53 | let &cpo=s:cpo_save 54 | "============================================================================= 55 | " vim600: set fdm=marker: 56 | -------------------------------------------------------------------------------- /after/ftplugin/ruby/ruby_brackets.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/lh-brackets/40af9b67424003a03e8384eab81256bfe535db0b/after/ftplugin/ruby/ruby_brackets.vim -------------------------------------------------------------------------------- /after/ftplugin/tex/tex_brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: ftplugin/tex/tex_brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.5.4 8 | " Created: 24th Mar 2008 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " tex-ftplugin that defines the default preferences regarding the 12 | " bracketing mappings we want to use. 13 | " 14 | "------------------------------------------------------------------------ 15 | " Note: 16 | " In order to override these default definitions, copy this file into a 17 | " directory that comes before the {rtp}/after/ftplugin/tex/ you choosed -- 18 | " typically $HOME/.vim/ftplugin/tex/ (:h 'rtp'). 19 | " Then, replace the calls to :Brackets, without the `-default` flag 20 | " 21 | " History: 22 | " TODO: 23 | " }}}1 24 | "============================================================================= 25 | " Buffer-local Definitions {{{1 26 | " Avoid local reinclusion {{{2 27 | if exists("b:loaded_ftplug_tex_brackets") && !exists('g:force_reload_ftplug_tex_brackets') 28 | finish 29 | endif 30 | let s:cpo_save=&cpo 31 | set cpo&vim 32 | let b:loaded_ftplug_tex_brackets = 354 33 | " Avoid local reinclusion }}}2 34 | 35 | "------------------------------------------------------------------------ 36 | " Brackets & all {{{2 37 | let b:marker_open = '<+' 38 | let b:marker_close = '+>' 39 | 40 | if ! lh#option#get('cb_no_default_brackets', 0) 41 | let b:cb_jump_on_close = 1 42 | Brackets ( ) -default -esc 43 | Brackets { } -default -esc 44 | Brackets [ ] -default -visual=0 -esc 45 | Brackets [ ] -default -insert=0 -trigger=[ 46 | Brackets $ $ -default -visual=0 47 | Brackets $ $ -default -insert=0 -trigger=$ 48 | endif 49 | 50 | " }}}1 51 | "------------------------------------------------------------------------ 52 | let &cpo=s:cpo_save 53 | "============================================================================= 54 | " vim600: set fdm=marker: 55 | -------------------------------------------------------------------------------- /after/ftplugin/vim/vim_brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: ftlugin/vim/vim_brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | " Created: 24th Mar 2008 9 | " Last Update: 17th May 2020 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " vim-ftplugin that defines the default preferences regarding the 13 | " bracketing mappings we want to use. 14 | " 15 | "------------------------------------------------------------------------ 16 | " Note: 17 | " In order to override these default definitions, copy this file into a 18 | " directory that comes before the {rtp}/after/ftplugin/vim/ you choosed -- 19 | " typically $HOME/.vim/ftplugin/vim/ (:h 'rtp'). 20 | " Then, replace the calls to :Brackets, without the `-default` flag 21 | " 22 | " TODO: 23 | " * Escapable "()" must also work with \%(\) 24 | 25 | "============================================================================= 26 | 27 | " Buffer-local Definitions {{{1 28 | " Avoid local reinclusion {{{2 29 | if exists("b:loaded_ftplug_vim_brackets") && !exists('g:force_reload_ftplug_vim_brackets') 30 | finish 31 | endif 32 | let s:cpo_save=&cpo 33 | set cpo&vim 34 | let b:loaded_ftplug_vim_brackets = 360 35 | " Avoid local reinclusion }}}2 36 | 37 | "------------------------------------------------------------------------ 38 | " Brackets & all {{{2 39 | "------------------------------------------------------------------------ 40 | 41 | " It seems that function() does not load anything with some versions of vim 42 | if !exists('lh#vim#brackets#lt') 43 | runtime autoload/lh/vim/brackets.vim 44 | endif 45 | 46 | if ! lh#option#get('cb_no_default_brackets', 0) 47 | let b:cb_jump_on_close = 1 48 | 49 | Brackets ( ) -default -esc 50 | Brackets " " -default -visual=0 -open=function('lh#vim#brackets#dquotes') -context!=comment 51 | Brackets < > -default -visual=0 -open=function('lh#vim#brackets#lt') 52 | Brackets < > -default -visual=1 -insert=0 -trigger=< 53 | endif 54 | 55 | " }}}1 56 | "------------------------------------------------------------------------ 57 | let &cpo=s:cpo_save 58 | "============================================================================= 59 | " vim600: set fdm=marker: 60 | -------------------------------------------------------------------------------- /autoload/lh/cpp/brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/cpp/brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | let s:k_version = 360 9 | " Created: 17th Mar 2008 10 | " Last Update: 05th Jan 2021 11 | "------------------------------------------------------------------------ 12 | " Description: 13 | " Functions that tune how some bracket characters should expand in C&C++ 14 | " TODO: 15 | " }}}1 16 | "============================================================================= 17 | 18 | let s:cpo_save=&cpo 19 | set cpo&vim 20 | "------------------------------------------------------------------------ 21 | " Does vim supports the new way to support redo/undo? 22 | let s:k_vim_supports_redo = has('patch-7.4.849') 23 | let s:k_move_prefix = s:k_vim_supports_redo ? "\U" : "" 24 | 25 | " ## Misc Functions {{{1 26 | " # Version {{{2 27 | function! lh#cpp#brackets#version() 28 | return s:k_version 29 | endfunction 30 | 31 | " # Debug {{{2 32 | let s:verbose = get(s:, 'verbose', 0) 33 | function! lh#cpp#brackets#verbose(...) 34 | if a:0 > 0 | let s:verbose = a:1 | endif 35 | return s:verbose 36 | endfunction 37 | 38 | function! s:Log(expr, ...) 39 | call call('lh#log#this',[a:expr]+a:000) 40 | endfunction 41 | 42 | function! s:Verbose(expr, ...) 43 | if s:verbose 44 | call call('s:Log',[a:expr]+a:000) 45 | endif 46 | endfunction 47 | 48 | function! lh#cpp#brackets#debug(expr) abort 49 | return eval(a:expr) 50 | endfunction 51 | 52 | " ## Functions {{{1 53 | 54 | " - Callback function that specializes the behaviour of '<' {{{2 55 | function! s:is_template(type) abort 56 | let type = matchstr(a:type, '\k\+\ze\s*$') 57 | call s:Verbose('check if template: "%1" -> "%2"', a:type, type) 58 | " 1- Check if this is a standard type registered in lh-cpp DB 59 | if !exists('s:has_lh_cpp') 60 | runtime autoload/lh/cpp/types.vim 61 | let s:has_lh_cpp = exists('*lh#cpp#types#version') && lh#cpp#types#version() >= 221 62 | endif 63 | if s:has_lh_cpp 64 | if lh#cpp#types#get_info(type).is_template() 65 | return 1 66 | endif 67 | endif 68 | " 2- ask ... who? 69 | " While tag database would have been a nice source of information, 70 | " unfortunately, it does not store any information that would tell 71 | " that a type, or a variable is template. 72 | " At best there is a `template` in the returned `'cmd'` field when 73 | " `template` occurs on the same line of the class/struct defined. 74 | " Also asking lh-clang would be too expensive. May be some day LSP 75 | " servers would return information on the current code... who knows? 76 | " 3- Return ... "no" 77 | return 0 78 | endfunction 79 | 80 | function! lh#cpp#brackets#lt() abort 81 | let c = col('.') - 1 82 | let l = getline('.') 83 | let l = strpart(l, 0, c) 84 | if (l =~ '^#\s*include\s*$' 85 | \ . '\|\U\{-}_cast\s*$' 86 | \ . '\|template\s*$' 87 | \ . '\|typename[^<]*$') 88 | \ || s:is_template(l) 89 | " \ . '\|\%(lexical\|dynamic\|reinterpret\|const\|static\)_cast\s*$' 90 | if lh#brackets#usemarks() 91 | return '!mark!' 92 | " NB: InsertSeq with "\" as parameter won't work in utf-8 => Prefer 93 | " "h" when motion is needed. 94 | " return '<>' . "!mark!\".lh#encoding#strlen(lh#marker#txt())."hi" 95 | " return '<>' . "!mark!\".lh#encoding#strlen(lh#marker#txt())."\i" 96 | else 97 | " return '<>' . "\" 98 | return '' 99 | endif 100 | else 101 | return '<' 102 | endif 103 | endfunction 104 | 105 | " - Callback function that specializes the behaviour of '{' {{{2 106 | function! lh#cpp#brackets#curly_open() abort 107 | let c = col('.') - 1 108 | let l = getline('.') 109 | let l = strpart(l, 0, c) 110 | let close = l =~ 'struct\|class\|enum\|union' ? '};' : '}' 111 | if lh#brackets#usemarks() 112 | return '{!cursorhere!'.close.'!mark!' 113 | else 114 | " return '<>' . "\" 115 | return '{!cursorhere!'.close 116 | endif 117 | endfunction 118 | 119 | " Function: lh#cpp#brackets#curly_close() {{{2 120 | function! lh#cpp#brackets#curly_close() abort 121 | let lin = line(".") 122 | let col = col(".") 123 | let lig = getline(lin) 124 | 125 | if lig[col-1] == '}' 126 | let nb = matchend(lig[(col-1) :], '};\=') 127 | return lh#map#_move_cursor_on_the_current_line(nb).lh#brackets#_jump_text(lig[(col+nb-1) :]) 128 | else 129 | " if the non white character is a curly bracket several lines later, 130 | " jump to it. Ignore any following semi-colon 131 | let pos = searchpos('\%#\_s*};\=', 'ce') 132 | 133 | if pos != [0,0] 134 | let delta_line = pos[0] - lin 135 | " We need to go to another line, this means, redo will be broken 136 | return s:k_move_prefix."\".repeat("\", delta_line) 137 | \ . lh#map#_move_cursor_on_the_current_line(pos[1]) 138 | \ . lh#brackets#_jump_text(getline(pos[0])[pos[1]:]) 139 | else 140 | return '}' 141 | endif 142 | endif 143 | endfunction 144 | 145 | " - Callback function that specializes the behaviour of '[', regarding C++11 attributes {{{2 146 | " Function: lh#cpp#brackets#square_open() {{{3 147 | function! lh#cpp#brackets#square_open() abort 148 | let col = col(".") 149 | let lig = getline(line(".")) 150 | 151 | let result = '[!cursorhere!]' 152 | if lig[(col-2):(col-1)] == '[]' 153 | return result 154 | else 155 | return result.s:Mark() 156 | endif 157 | endfunction 158 | 159 | " Function: lh#cpp#brackets#square_close() {{{3 160 | function! lh#cpp#brackets#square_close() abort 161 | let col = col(".") 162 | let lig = getline(line(".")) 163 | 164 | if lig[col-1] == ']' 165 | let nb = matchend(lig[(col-1) :], ']\+') 166 | return lh#map#_move_cursor_on_the_current_line(nb).lh#brackets#_jump_text(lig[(col+nb-1) :]) 167 | else 168 | return ']' 169 | endif 170 | endfunction 171 | 172 | function! s:Mark() abort " {{{2 173 | return lh#brackets#usemarks() 174 | \ ? "!mark!" 175 | \ : "" 176 | endfunction 177 | 178 | " Function: lh#cpp#brackets#semicolon() {{{2 179 | " expected to be called from insert mode 180 | function! lh#cpp#brackets#semicolon() abort 181 | let line = getline('.') 182 | let col = col('.') - 1 183 | 184 | " Cursor is within a "for"/"if" context? 185 | if line[0:col] =~ '\v<(for|if)>\s*\(' 186 | " TODO: better detection of context with searchpair() 187 | if line[col : -1] =~ '^;' 188 | call s:Verbose("Within for/if && before a semicolon") 189 | " Merge only with the next semicolon; ignore following ones! 190 | " => 3rd param == empty string 191 | return lh#brackets#close_all_and_jump_to_last_on_line(';', {'to_merge': '', 'repeat': ''}) 192 | else 193 | call s:Verbose("Within for/if") 194 | return ';' 195 | endif 196 | endif 197 | 198 | let rem = line[col : -1] 199 | 200 | if rem =~ '^"\=\('.lh#marker#txt('.\{-}').'\)\=[)\]]\+' 201 | call s:Verbose("Within brackets -> jump") 202 | return lh#brackets#close_all_and_jump_to_last_on_line(')]', {'to_merge': ';'}) 203 | elseif rem =~ '^;' 204 | call s:Verbose("Before a semicolon -> jump") 205 | return lh#brackets#close_all_and_jump_to_last_on_line(';', {'to_merge': ''}) 206 | endif 207 | 208 | " Otherwise 209 | return ';' 210 | endfunction 211 | 212 | " Function: lh#cpp#brackets#move_semicolon_back_to_string_context() {{{3 213 | function! lh#cpp#brackets#move_semicolon_back_to_string_context() abort 214 | " It seem c-o leaves the insert mode for good. Thats odd. 215 | " BUG? -> return "\\F\";" 216 | " Let's do n- instead 217 | let l=getline('.')[:col(".")-3] 218 | let end = matchstr(l, '"\s*)\+$') 219 | let lend= lh#encoding#strlen(end) 220 | let move = lh#position#move_n("\", lend) 221 | return "\".move.";" 222 | endfunction 223 | 224 | " }}}1 225 | "------------------------------------------------------------------------ 226 | let &cpo=s:cpo_save 227 | "============================================================================= 228 | " vim600: set fdm=marker: 229 | -------------------------------------------------------------------------------- /autoload/lh/html/brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/html/brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | let s:k_version = '360' 9 | " Created: 24th Mar 2008 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " Functions that tune how some bracket characters should expand in C&C++ 13 | " }}}1 14 | "============================================================================= 15 | 16 | let s:cpo_save=&cpo 17 | set cpo&vim 18 | 19 | " ## Misc Functions {{{1 20 | " # Version {{{2 21 | function! lh#html#brackets#version() 22 | return s:k_version 23 | endfunction 24 | 25 | " # Debug {{{2 26 | let s:verbose = get(s:, 'verbose', 0) 27 | function! lh#html#brackets#verbose(...) 28 | if a:0 > 0 | let s:verbose = a:1 | endif 29 | return s:verbose 30 | endfunction 31 | 32 | function! s:Log(expr, ...) abort 33 | call call('lh#log#this',[a:expr]+a:000) 34 | endfunction 35 | 36 | function! s:Verbose(expr, ...) abort 37 | if s:verbose 38 | call call('s:Log',[a:expr]+a:000) 39 | endif 40 | endfunction 41 | 42 | function! lh#html#brackets#debug(expr) abort 43 | return eval(a:expr) 44 | endfunction 45 | 46 | "------------------------------------------------------------------------ 47 | " ## Hooks {{{1 48 | function! lh#html#brackets#lt() abort 49 | return s:Insert('<') 50 | endfunction 51 | 52 | function! lh#html#brackets#gt() abort 53 | return s:Insert('>') 54 | endfunction 55 | 56 | " '<' automatically inserts its counter part 57 | " '>' reach the next '>' 58 | " While '<'+'<' inserts '<' and '<'+'>' inserts '>' 59 | " 60 | " And '<' + '/' will insert the closing tag associated to the previous one 61 | " not already closed. 62 | 63 | " Which==0 <=> '<'; 64 | function! s:Insert(which) abort 65 | let column = col(".") 66 | let lig = getline(".") 67 | if lig[column-2] == '<' 68 | let ret = "\&". ((a:which == '<') ? 'lt;' : 'gt;') 69 | if lig[column-1] == '>' 70 | let ret = "\" . ret 71 | endif 72 | let marker = lh#marker#txt() 73 | if strpart(lig, column) =~ '\V'.escape(marker, '\') 74 | let ret .= substitute(marker, '.', "\", 'g') 75 | endif 76 | return ret 77 | else 78 | if a:which == '<' | return '!mark!' 79 | elseif lig[column-1] == '>' | return lh#brackets#_jump() 80 | else | return '>' 81 | endif 82 | endif 83 | endfunction 84 | 85 | " 86 | function! s:CloseTag() abort 87 | let ret = '/' 88 | let column = col(".") 89 | let lig = getline(line(".")) 90 | if lig[column-2] == '<' 91 | " find the previous match ... perhaps thanks to matchit 92 | let ret = "\<" 93 | if lig[column-1] == '>' 94 | let ret = "\\" . ret 95 | endif 96 | endif 97 | return ret; 98 | endfunction 99 | 100 | let &cpo=s:cpo_save 101 | "============================================================================= 102 | " vim600: set fdm=marker: 103 | -------------------------------------------------------------------------------- /autoload/lh/map.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/map.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | let s:k_version = '360' 9 | " Created: 03rd Nov 2015 10 | " Last Update: 23rd Jun 2024 11 | "------------------------------------------------------------------------ 12 | " Description: 13 | " API plugin: Several mapping-oriented functions 14 | " 15 | "------------------------------------------------------------------------ 16 | " History: 17 | " v3.6.0 Move functions into autoload plugin 18 | " Fix line shifting when CoC Annotate suggestions... 19 | " v3.5.2 Improve logs 20 | " v3.2.1 Fix regression with `set et` 21 | " v3.2.0 Add `lh#map#4_this_context()` 22 | " Fix tw issue, again 23 | " Deprecates lh#dev#reinterpret_escaped_char() 24 | " v3.1.2 Fix Issue 9 (when g:usemarks is false) 25 | " v3.0.8 Fix Indenting issue when surrounding 26 | " v3.0.6 Fix Indenting regression 27 | " v3.0.5 Use lh#log() framework 28 | " Fix Indenting issue when indentation changes between opening and 29 | " closing brackets 30 | " v3.0.4 Support definitions like ":Bracket \Q{ } -trigger=µ" 31 | " Some olther mappings may not work anymore. Alas I have no tests 32 | " for them ^^' 33 | " v3.0.1 Support older versions of vim, thanks to Troy Curtis Jr 34 | " v3.0.0 !mark! & co have been deprecated as mappings 35 | " v2.3.0 functions moved from plugin/misc_map.vim 36 | " TODO: 37 | " * Simplify the way mappings are defined, hopefully to get rid of 38 | " lh#mapping#reinterpret_escaped_char() 39 | " }}}1 40 | "============================================================================= 41 | 42 | let s:cpo_save=&cpo 43 | set cpo&vim 44 | 45 | " Does vim supports the new way to support redo/undo? 46 | let s:k_vim_supports_redo = has('patch-7.4.849') 47 | let s:k_move_prefix = s:k_vim_supports_redo ? "\U" : "" 48 | 49 | "------------------------------------------------------------------------ 50 | " ## Misc Functions {{{1 51 | " # Version {{{2 52 | function! lh#map#version() 53 | return s:k_version 54 | endfunction 55 | 56 | " # Debug {{{2 57 | let s:verbose = get(s:, 'verbose', 0) 58 | function! lh#map#verbose(...) 59 | if a:0 > 0 | let s:verbose = a:1 | endif 60 | return s:verbose 61 | endfunction 62 | 63 | function! s:Log(...) 64 | call call('lh#log#this', a:000) 65 | endfunction 66 | 67 | function! s:Verbose(...) 68 | if s:verbose 69 | call call('s:Log', a:000) 70 | endif 71 | endfunction 72 | 73 | function! lh#map#debug(expr) 74 | return eval(a:expr) 75 | endfunction 76 | 77 | " # Helpers {{{2 78 | " s:getSNR([func_name]) {{{3 79 | function! s:getSNR(...) 80 | if !exists("s:SNR") 81 | let s:SNR=matchstr(expand(''), '\d\+_\zegetSNR$') 82 | endif 83 | return s:SNR . (a:0>0 ? (a:1) : '') 84 | endfunction 85 | 86 | "------------------------------------------------------------------------ 87 | " ## Exported functions {{{1 88 | 89 | " # Misc functions {{{2 90 | 91 | " Function: lh#map#eat_char(pat) {{{3 92 | " Thanks to the VIM Mailing list ; 93 | " Note: In it's foo.vim, Benji Fisher maintains a more robust version of this 94 | " function; see: http://www.vim.org/script.php?script_id=72 95 | " NB: To make it work with VIM 5.x, replace the '? :' operator with an 'if 96 | " then' test. 97 | " This version does not support multi-bytes characters. 98 | " Todo: add support for 99 | function! lh#map#eat_char(pat) abort 100 | let c = nr2char(getchar()) 101 | return (c =~ a:pat) ? '' : c 102 | endfunction 103 | 104 | " # Sequence functions {{{2 105 | 106 | " Function: lh#map#4_this_context(key, rule, sequence[, default]) {{{3 107 | function! s:match(syn) dict 108 | return a:syn =~? self.context 109 | endfunction 110 | function! s:dont_match(syn) dict 111 | return a:syn !~? self.context 112 | endfunction 113 | function! s:new_matcher(context) abort 114 | let matcher = lh#object#make_top_type({}) 115 | if type(a:context) == type('') 116 | let matcher.recognizes = function(s:getSNR('match')) 117 | let matcher.context = a:context 118 | elseif has_key(a:context, 'is') 119 | let matcher.recognizes = function(s:getSNR('match')) 120 | let matcher.context = a:context.is 121 | elseif has_key(a:context, "isn't") 122 | let matcher.recognizes = function(s:getSNR('dont_match')) 123 | let matcher.context = a:context["isn't"] 124 | else 125 | throw "Unexpected argument ".string(a:context) 126 | endif 127 | return matcher 128 | endfunction 129 | 130 | function! lh#map#4_this_context(key, rule, sequence, ...) abort 131 | let syn = lh#syntax#name_at(line('.'), col('.')-1, 1) 132 | let context = s:new_matcher(a:rule) 133 | if context.recognizes(syn) 134 | return lh#mapping#reinterpret_escaped_char(a:sequence) 135 | elseif a:0 > 0 136 | return lh#mapping#reinterpret_escaped_char(a:1) 137 | else 138 | return a:key 139 | endif 140 | endfunction 141 | 142 | " Function: lh#map#4_these_contexts(key, ...) {{{3 143 | " Exactly the same purpose than lh#map#context(), but even more precise. It does 144 | " not make any assumption for strings-, comments-, characters- and 145 | " doxygen-context. 146 | " Returns: 147 | " - interpreted {seq_i} within {syn_i} context, 148 | " - interpreted {default-seq} otherwise ; default value: {key} 149 | function! lh#map#4_these_contexts(key, ...) abort 150 | let syn = lh#syntax#name_at(line('.'), col('.')-1, 1) 151 | let i = 1 152 | while i < a:0 153 | if (a:{i} =~ '^\(\k\|\\|\)\+$') && (syn =~? a:{i}) 154 | return lh#mapping#reinterpret_escaped_char(a:{i+1}) 155 | endif 156 | let i += 2 157 | endwhile 158 | " Else: default case 159 | if i == a:0 160 | return lh#mapping#reinterpret_escaped_char(a:{a:0}) 161 | else 162 | return a:key 163 | endif 164 | endfunction 165 | 166 | " Function: lh#map#context(key, ...) {{{3 167 | " Exactly the same purpose than lh#map#no_context(), but more precise. 168 | " Returns: 169 | " - {key} within string, character or comment context, 170 | " - interpreted {seq_i} within {syn_i} context, 171 | " - interpreted {default-seq} otherwise ; default value: {key} 172 | function! lh#map#context(key, ...) abort 173 | let syn = lh#syntax#name_at(line('.'), col('.')-1, 1) 174 | if syn =~? '\vcomment|string|character|doxygen' 175 | return a:key 176 | else 177 | return call('lh#map#4_these_contexts', [a:key]+a:000) 178 | endif 179 | endfunction 180 | 181 | " Function: lh#map#no_context(key, seq) {{{3 182 | " Purpose: 183 | " Regarding the context of the current position of the cursor, it returns 184 | " either the value of key or the interpreted value of sequence. 185 | " Parameters: 186 | " - returned while whithin comments, strings or characters 187 | " - returned otherwise. In order to enable the interpretation of 188 | " escaped caracters, must be a double-quoted string. A 189 | " backslash must be inserted before every '<' and '>' sign. 190 | " Actually, the '<' after the second one (included) must be 191 | " backslashed twice. 192 | " Example: 193 | " A mapping of 'if' for C programmation: 194 | " Iabbr if =lh#map#no_context("if ", 195 | " \ '\if () {\}\?)\i') 196 | function! s:syn_context() abort 197 | return synIDattr(synID(line('.'),col('.')-1,1),'name') 198 | endfunction 199 | 200 | function! lh#map#no_context(key, seq) abort 201 | let syn = lh#syntax#name_at(line('.'), col('.')-1, 1) 202 | if syn =~? '\vcomment|string|character|doxygen' 203 | return a:key 204 | else 205 | return lh#mapping#reinterpret_escaped_char(a:seq) 206 | endif 207 | endfunction 208 | 209 | " Function: lh#map#no_context2(key, sequence) {{{3 210 | " Purpose: 211 | " Exactly the same purpose than lh#map#no_context(). 212 | " There is a slight difference, the previous function is really annoying when we 213 | " want to use variables like 'tarif' in the code. 214 | " So this function also returns when the character before the current 215 | " cursor position is not a keyword character ('h: iskeyword' for more info). 216 | " Hint: 217 | " Use lh#map#no_context2() for mapping keywords like 'if', etc. and lh#map#no_context() 218 | " for other mappings like parenthesis, punctuations signs, and so on. 219 | function! lh#map#no_context2(key, sequence) abort 220 | let c = col('.')-1 221 | let l = line('.') 222 | let syn = lh#syntax#name_at(l,c, 1) 223 | if syn =~? '\vcomment|string|character|doxygen' 224 | return a:key 225 | elseif getline(l)[c-1] =~ '\k' 226 | return a:key 227 | else 228 | return lh#mapping#reinterpret_escaped_char(a:seq) 229 | endif 230 | endfunction 231 | 232 | " Function: lh#map#build_map_seq(seq) {{{3 233 | " Purpose: 234 | " This function is to be used to generate the sequences used by the 235 | " «lh#map#no_context» functions. 236 | " It considers that every «!.\{-}!» pattern is associated to an INSERT-mode 237 | " mapping and expands it. 238 | " It is used to define marked mappings ; cf 239 | let s:k_mappings_translation = { 240 | \ '!mark!' : 'MarkersInsertMark', 241 | \ '!jump!' : 'MarkersJumpF', 242 | \ '!jumpB!' : 'MarkersJumpB', 243 | \ '!jump-and-del!' : 'MarkersJumpAndDelF', 244 | \ '!bjump-and-del!': 'MarkersJumpAndDelB' 245 | \ } 246 | 247 | function! lh#map#build_map_seq(seq) abort 248 | let r = '' 249 | let s = a:seq 250 | while strlen(s) != 0 " For every '!.*!' pattern, extract it 251 | let r .= substitute(s,'\v^(.{-})((!\k{-1,}!)(.*))=$', '\1', '') 252 | let c = substitute(s,'\v^(.{-})((!\k{-1,}!)(.*))=$', '\3', '') 253 | let s = substitute(s,'\v^(.{-})((!\k{-1,}!)(.*))=$', '\4', '') 254 | " !mark! & cie need translation now 255 | let c = get(s:k_mappings_translation, c, c) 256 | let m = maparg(c,'i') 257 | if strlen(m) != 0 258 | silent exe 'let m="' . substitute(m, '<\(.\{-1,}\)>', '"."\\<\1>"."', 'g') . '"' 259 | if has('iconv') " small workaround for !imappings! in UTF-8 on linux 260 | let m = iconv(m, "latin1", &encoding) 261 | endif 262 | let r .= m 263 | else 264 | let r .= c 265 | endif 266 | endwhile 267 | return lh#mapping#reinterpret_escaped_char(r) 268 | endfunction 269 | 270 | " Function: lh#map#smart_insert_seq1(key, expr1, expr2) {{{3 271 | function! lh#map#smart_insert_seq1(key, expr1, expr2) abort 272 | if lh#brackets#usemarks() 273 | return lh#map#no_context(a:key,lh#map#build_map_seq(a:expr2)) 274 | else 275 | return lh#map#no_context(a:key,a:expr1) 276 | endif 277 | endfunction 278 | 279 | " Function: lh#map#smart_insert_seq2(key, expr, ...) {{{3 280 | function! lh#map#smart_insert_seq2(key, expr, ...) abort 281 | " let rhs = escape(a:expr, '\') 282 | let rhs = a:expr 283 | 284 | " Strip marks (/placeholders) if they are not wanted 285 | if ! lh#brackets#usemarks() 286 | let rhs = substitute(rhs, '\v!mark!|\<+\k+\>', '', 'g') 287 | endif 288 | " Interpret the sequence if it is meant to 289 | if rhs =~ '\m!\(mark\%(here\)\=\|movecursor\)!' 290 | " may be, the regex should be '\m!\S\{-}!' 291 | " let rhs = lh#map#build_map_seq(escape(rhs, '\')) 292 | let rhs = lh#map#build_map_seq(rhs) 293 | elseif rhs =~ '<+.\{-}+>' 294 | " @todo: add a move to cursor + jump/select 295 | let rhs = substitute(rhs, '<+\(.\{-}\)+>', "!cursorhere!&", '') 296 | let rhs = substitute(rhs, '<+\(.\{-}\)+>', "\=lh#marker#txt(".string('\1').")\", 'g') 297 | let rhs .= "!movecursor!" 298 | " let rhs = lh#map#build_map_seq(escape(rhs, '\'))."\\@=lh#marker#_jump({'direction':1, 'mode':'n'})\" 299 | let rhs = lh#map#build_map_seq(rhs."\\@=lh#marker#_jump({'direction':1, 'mode':'n'})\") 300 | endif 301 | " Build & return the context dependent sequence to insert 302 | if a:0 > 0 303 | return lh#map#4_this_context(a:key, a:1, rhs) 304 | else 305 | return lh#map#no_context(a:key,rhs) 306 | endif 307 | endfunction 308 | 309 | " Function: lh#map#insert_seq(key, seq[, context]) {{{3 310 | function! lh#map#insert_seq(key, seq, ...) abort 311 | " TODO: if no escape nor newline -> use s:k_move_prefix 312 | let mark = a:seq =~ '!cursorhere!' 313 | let s:gotomark = '' 314 | let seq = lh#mapping#reinterpret_escaped_char(a:seq) 315 | let seq .= (mark ? '!movecursor!' : '') 316 | 317 | let cleanup = lh#on#exit() 318 | \.register('iunmap !cursorhere!') 319 | \.register('iunmap !movecursor!') 320 | try 321 | " dummy mappings used to move the cursor auround 322 | inoremap !cursorhere! =lh#map#_cursor_here() 323 | inoremap !movecursor! =lh#map#_goto_mark() 324 | " Build the sequence to insert 325 | let res = call('lh#map#smart_insert_seq2', [a:key, seq] + a:000) 326 | finally 327 | " purge the dummy mappings 328 | call cleanup.finalize() 329 | endtry 330 | call s:Verbose(strtrans(res)) 331 | return res 332 | endfunction 333 | 334 | " # Surrounding functions {{{2 335 | 336 | " Function: lh#map#surround_by_substitute(begin, end, isLine, isIndented, goback, mustInterpret, ...) {{{3 337 | " @Overload that does not rely on '>a + '0) ? (a:1) : (a:begin)) 342 | endif 343 | 344 | let save_a = @a 345 | try 346 | let begin = a:begin 347 | let end = a:end 348 | if a:isLine 349 | let begin .= "\n" 350 | let end = "\n" . end 351 | endif 352 | " Hack to know what is selected without altering any register 353 | normal! gv"ay 354 | let seq = begin . @a . end 355 | let goback = '' 356 | 357 | if a:mustInterpret 358 | inoremap !cursorhere! :call lh#map#_cursor_here()a 359 | " inoremap !movecursor! :call lh#map#_goto_mark()a 360 | inoremap !movecursor! :call lh#map#_goto_mark()a=lh#map#_fix_indent() 361 | 362 | if ! lh#brackets#usemarks() 363 | let seq = substitute(seq, '!mark!', '', 'g') 364 | endif 365 | if (begin =~ '!cursorhere!') 366 | let goback = lh#map#build_map_seq('!movecursor!') 367 | endif 368 | let seq = lh#map#build_map_seq(seq) 369 | endif 370 | let res = 'gv"_c'.seq 371 | exe "normal! ".res 372 | return goback 373 | finally 374 | let @a = save_a 375 | " purge the internal mappings 376 | silent! iunmap !cursorhere! 377 | silent! iunmap !movecursor! 378 | endtry 379 | endfunction 380 | 381 | " Function: lh#map#surround(begin, end, isLine, isIndented, goback, mustInterpret, ...) {{{3 382 | function! lh#map#surround(begin, end, isLine, isIndented, goback, mustInterpret, ...) range abort 383 | if lh#marker#is_a_marker() 384 | return 'gv"_c'.((a:0>0) ? (a:1) : (a:begin)) 385 | endif 386 | 387 | " Prepare {a:begin} and {a:end} to be inserted around the visual selection 388 | let begin = a:begin 389 | let end = a:end 390 | let goback = a:goback 391 | if a:mustInterpret 392 | " internal mappings 393 | " should be better for !cursorhere! as it does not move the cursor 394 | " But only works correctly. 395 | inoremap !cursorhere! :call lh#map#_cursor_here()a 396 | " Weird: cursorpos1 & 2 require an not 397 | inoremap !cursorpos1! :call lh#map#_cursor_here(1) 398 | inoremap !cursorpos2! :call lh#map#_cursor_here(2) 399 | " ....a is better for !movecursor! as it leaves the cursor `in' 400 | " insert-mode... does not; that's odd. 401 | " inoremap !movecursor! a=lh#map#_goto_mark().lh#map#_fix_indent() 402 | inoremap !movecursor! :call lh#map#_goto_mark(1)a=lh#map#_fix_indent() 403 | inoremap !movecursor2! :call lh#map#_goto_end_mark()a=lh#map#_fix_indent() 404 | 405 | " Check whether markers must be used 406 | if !lh#brackets#usemarks() 407 | let begin = substitute(begin, '!mark!', '', 'g') 408 | let end = substitute(end, '!mark!', '', 'g') 409 | endif 410 | " Override the value of {goback} if "!cursorhere!" is used. 411 | if (begin =~ '!cursorhere!') 412 | let goback = lh#map#build_map_seq('!movecursor!') 413 | " let goback = "a\=".'lh#map#_goto_mark().lh#map#_fix_indent()'."\" 414 | endif 415 | if (end =~ '!cursorhere!') 416 | let begin = '!cursorpos1!'.begin.'!cursorpos2!' 417 | let goback = lh#map#build_map_seq('!movecursor2!') 418 | if !a:isLine && (line("'>") == line("'<")) && ('V'==visualmode()) 419 | \ && (getline("'>")[0] =~ '\s') 420 | :normal! 0"_dw 421 | " TODO: fix when &selection == exclusive 422 | endif 423 | endif 424 | " Transform {begin} and {end} (interpret the "inlined" mappings) 425 | let begin = lh#map#build_map_seq(begin) 426 | let end = lh#map#build_map_seq(end) 427 | 428 | " purge the internal mappings 429 | iunmap !cursorhere! 430 | iunmap !cursorpos1! 431 | iunmap !cursorpos2! 432 | iunmap !movecursor! 433 | endif 434 | " Call the function that really insert the text around the selection 435 | :'<,'>call lh#map#insert_around_visual(begin, end, a:isLine, a:isIndented) 436 | " Return the nomal-mode sequence to execute at the end. 437 | " let g:goback =goback 438 | return goback 439 | endfunction 440 | 441 | " Function: lh#map#insert_around_visual(begin,end,isLine,isIndented) {{{3 442 | function! lh#map#insert_around_visual(begin,end,isLine,isIndented) range abort 443 | if &ft == 'python' && a:isIndented && a:isLine 444 | " let g:action= "normal! gv>`>o".a:end."\`".a:begin 445 | exe "normal! gv>`>o\".a:end."\`".a:begin 446 | return 447 | endif 448 | 449 | " Note: to detect a marker before surrounding it, use Surround() 450 | " Changing 'paste' changes many settings => we record them 451 | let cleanup = lh#on#exit() 452 | \.restore('&paste') 453 | \.restore('&autoindent') 454 | \.restore('&expandtab') 455 | \.restore('&formatoptions') 456 | \.restore('&revins') 457 | \.restore('&ruler') 458 | \.restore('&showmatch') 459 | \.restore('&smartindent') 460 | \.restore('&smarttab') 461 | \.restore('&softtabstop') 462 | \.restore('&tw') 463 | \.restore('&wrapmargin') 464 | let crt_expandtab = &expandtab 465 | try 466 | set paste 467 | let &expandtab = crt_expandtab 468 | " 'H' stands for 'High' ; 'B' stands for 'Bottom' 469 | " 'L' stands for 'Left', 'R' for 'Right' 470 | let HL = "` jump between stuffs 479 | if a:isLine == 1 480 | let HR="\".HR 481 | let BL .="\" 482 | elseif a:isLine == 2 483 | let HL = "` defined 490 | let HR="\".HR 491 | let BR="\".BR 492 | else " Otherwise like LaTeX, VIM 493 | let HR .=":>\" 494 | let BR .=":<\" 495 | endif 496 | let BL='>'.BL " }}} 497 | else " -----------------------Version 6.xx 498 | let HR .="gv``=" 499 | endif 500 | elseif type(a:isIndented) == type('') 501 | let BL = a:isIndented . BL " move the previous lines 502 | let HR .="gv``=" " indent the new line inserted 503 | endif 504 | " The substitute is here to compensate a little problem with HTML tags 505 | " let g:action= "normal! gv". BL.substitute(a:end,'>',"\>",'').BR.HL.a:begin.HR 506 | call s:Verbose(strtrans("normal! gv". BL.substitute(a:end,'>',"\>",'').BR.HL.a:begin.HR)) 507 | if s:verbose >= 2 508 | debug exe "normal! gv". BL.substitute(a:end,'>',"\>",'').BR.HL.a:begin.HR 509 | else 510 | silent exe "normal! gv". BL.substitute(a:end,'>',"\>",'').BR.HL.a:begin.HR 511 | endif 512 | " 'gv' is used to refocus on the current visual zone 513 | " call confirm(strtrans( "normal! gv". BL.a:end.BR.HL.a:begin.HR), "&Ok") 514 | finally 515 | call cleanup.finalize() 516 | endtry 517 | endfunction 518 | 519 | "------------------------------------------------------------------------ 520 | " ## Internal functions {{{1 521 | 522 | " # Cursor moving {{{2 523 | " Function: s:find_unused_mark() {{{3 524 | function! s:find_unused_mark() abort 525 | let mark = lh#mark#find_first_unused() 526 | if mark == -1 527 | " TODO: return the first mark found which is before the cursor 528 | let mark = get(g:, 'lh#map#default_mark', "'M") 529 | endif 530 | return [mark, getpos(mark)] 531 | endfunction 532 | 533 | " Mark where the cursor should be at the end of the insertion 534 | 535 | " Function: lh#map#_cursor_here(...) {{{3 536 | function! lh#map#_cursor_here(...) abort 537 | let s:old_indent = indent(line('.')) 538 | let mark = s:find_unused_mark() 539 | let pos = getpos('.') 540 | call setpos(mark[0], pos) 541 | call s:Verbose('Using mark %1', mark) 542 | if a:0 > 0 543 | let s:goto_mark_{a:1} = mark 544 | let res = s:goto_mark_{a:1} 545 | else 546 | let s:goto_mark = mark + [virtcol(mark[0])] 547 | let res = s:goto_mark 548 | endif 549 | call s:Verbose("Record cursor %1 with mark %2: @ %3 | indent=%4 => %5", get(a:, 1, ''), mark[0], pos, s:old_indent, res) 550 | return '' 551 | endfunction 552 | 553 | " Function: lh#map#_goto_mark([old_behaviour]) {{{3 554 | function! lh#map#_goto_mark(...) abort 555 | " We fetch the updated mark position. This is important in case automated 556 | " line breaking occurs (i.e. when cursor column exceeds 'tw'). Indeed, in 557 | " that case, the mark is automatically moved, and we need to use it's last 558 | " know position. 559 | let markpos = getpos(s:goto_mark[0]) 560 | let goto_lin = markpos[1] 561 | let old_vcol = s:goto_mark[2] 562 | let goto_vcol = virtcol(s:goto_mark[0]) 563 | call s:Verbose('Returning to mark %1 @ %2 v=%3 from v=%4', s:goto_mark[0], markpos, goto_vcol, virtcol('.')) 564 | " Bug: if line is empty, indent() value is 0 => expect old_indent to be the One 565 | let crt_indent = indent(goto_lin) 566 | let s:fix_indent = s:old_indent - crt_indent 567 | call s:Verbose('fix indent <- %1 (old_indent:%2 - crt_indent:%3)', s:fix_indent, s:old_indent, crt_indent) 568 | 569 | try 570 | if s:fix_indent != 0 571 | let goto_vcol -= s:fix_indent 572 | call s:Verbose('goto_vcol -= %1 (old_indent:%3 - crt_indent:%4) => %2', s:fix_indent, goto_vcol, s:old_indent, crt_indent) 573 | endif 574 | let new_behaviour = (a:0 > 0) ? (!a:1) : 1 575 | if new_behaviour && goto_lin == line('.') 576 | " Same line -> eligible for moving the cursor 577 | " TODO: handle reindentation changes 578 | let delta = goto_vcol - virtcol('.') " Doesn't work with CoC type annotations for Python 579 | " let delta = old_vcol - virtcol('.') " Works with CoC type annotations for Python 580 | let move = lh#map#_move_cursor_on_the_current_line(delta) 581 | return move 582 | else 583 | " * insert-mode "^Fif(!cursor!)..." does not trigger fix_indent 584 | " * visual-mode surrounding "`>", "`r" 588 | " -> the mark has not followed the indent change 589 | " * However, with virtcol() if &expandtab is false, and we're within 590 | " curly brackets, things change... 591 | " * virtual columns are important because 592 | " - "\t" occupies 1 byte, but several columns 593 | " - "«" occupies 2 bytes, but only one column 594 | " * "|" takes a virtual column number 595 | """ No! 596 | ""let pos = getpos(s:goto_mark[0]) 597 | ""call s:Verbose("Restore cursor to mark %1: %2", s:goto_mark[0], pos) 598 | ""call setpos('.', pos) 599 | 600 | """ No! 601 | ""let goto_col = markpos[2] 602 | ""let goto_col -= s:fix_indent 603 | """ " uses {lig}'normal! {col}|' because of the possible reindent 604 | ""call s:Verbose("Restore cursor to %1normal! %2|", goto_lin, goto_col) 605 | ""execute goto_lin . 'normal! ' . (goto_col) . '|' 606 | 607 | if s:fix_indent == 0 608 | call s:Verbose("No indent fixed ; restore cursor to mark %1: %2", s:goto_mark[0], markpos) 609 | call setpos('.', markpos) 610 | else 611 | let goto_vcol = old_vcol - s:fix_indent 612 | call s:Verbose("new virtcol = old (%1) - fix_indent(%2) => %3", old_vcol, s:fix_indent, goto_vcol) 613 | " goto_lin has already been fixed! 614 | call s:Verbose("Indent needs to be fixed ; restore cursor to %1normal! %2|", goto_lin, goto_vcol) 615 | execute goto_lin . 'normal! ' . (goto_vcol) . '|' 616 | 617 | endif 618 | 619 | """ No! 620 | "" call cursor(goto_lin, goto_col) 621 | return '' 622 | endif 623 | finally 624 | " Restore the mark to [0,0,0,0] or to what it was 625 | call setpos(s:goto_mark[0], s:goto_mark[1]) 626 | endtry 627 | endfunction 628 | 629 | " Function: lh#map#_goto_end_mark() {{{3 630 | function! lh#map#_goto_end_mark() abort 631 | " Bug: if line is empty, indent() value is 0 => expect old_indent to be the One 632 | let markpos = getpos(s:goto_mark[0]) 633 | let markpos_1 = getpos(s:goto_mark_1[0]) 634 | let markpos_2 = getpos(s:goto_mark_2[0]) 635 | let goto_lin = markpos[1] 636 | let goto_lin_1 = markpos_1[1] 637 | let goto_lin_2 = markpos_2[1] 638 | let goto_col = markpos[2] 639 | let goto_col_1 = markpos_1[2] 640 | let goto_col_2 = markpos_2[2] 641 | 642 | try 643 | let crt_indent = indent(goto_lin) 644 | if crt_indent < s:old_indent 645 | let s:fix_indent = s:old_indent - crt_indent 646 | else 647 | let s:old_indent = crt_indent - s:old_indent 648 | let s:fix_indent = 0 649 | endif 650 | if s:old_indent != 0 651 | let goto_col += s:old_indent 652 | endif 653 | if goto_lin != goto_lin_2 654 | " TODO: !! 655 | else 656 | let goto_col += goto_col_2 - goto_col_1 657 | endif 658 | call cursor(goto_lin, goto_col) 659 | return '' 660 | finally 661 | " Restore the marks to [0,0,0,0] or to what they were 662 | call setpos(s:goto_mark[0], s:goto_mark[1]) 663 | call setpos(s:goto_mark_1[0], s:goto_mark_1[1]) 664 | call setpos(s:goto_mark_2[0], s:goto_mark_2[1]) 665 | endtry 666 | endfunction 667 | 668 | " Function: lh#map#_fix_indent() {{{3 669 | function! lh#map#_fix_indent() abort 670 | return '' 671 | " return repeat( ' ', s:fix_indent) 672 | endfunction 673 | 674 | 675 | " Function: lh#map#_move_cursor_on_the_current_line(offset) {{{3 676 | " This function tries to move the cursor in order to maintain redo-ability of 677 | " the text inserted. 678 | " See vim patch 7.4.849 679 | function! lh#map#_move_cursor_on_the_current_line(offset) abort 680 | let abs_offset = lh#math#abs(a:offset) 681 | call s:Verbose("Moving cursor %1 x %2", abs_offset, a:offset>0 ? "right" : "left") 682 | let move = a:offset > 0 ? "\" : "\" 683 | return repeat(s:k_move_prefix.move, abs_offset) 684 | endfunction 685 | 686 | "------------------------------------------------------------------------ 687 | 688 | " }}}1 689 | "------------------------------------------------------------------------ 690 | let &cpo=s:cpo_save 691 | "============================================================================= 692 | " vim600: set fdm=marker: 693 | -------------------------------------------------------------------------------- /autoload/lh/markdown/brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/markdown/brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | let s:k_version = 360 9 | " Created: 14th Mar 2014 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " Tweaking of lh-brackets functions for markdown 13 | " }}}1 14 | "============================================================================= 15 | 16 | let s:cpo_save=&cpo 17 | set cpo&vim 18 | "------------------------------------------------------------------------ 19 | " ## Misc Functions {{{1 20 | " # Version {{{2 21 | function! lh#markdown#brackets#version() 22 | return s:k_version 23 | endfunction 24 | 25 | " # Debug {{{2 26 | let s:verbose = 0 27 | function! lh#markdown#brackets#verbose(...) 28 | if a:0 > 0 | let s:verbose = a:1 | endif 29 | return s:verbose 30 | endfunction 31 | 32 | function! s:Verbose(expr) 33 | if s:verbose 34 | echomsg a:expr 35 | endif 36 | endfunction 37 | 38 | function! lh#markdown#brackets#debug(expr) 39 | return eval(a:expr) 40 | endfunction 41 | 42 | 43 | "------------------------------------------------------------------------ 44 | " ## Exported functions {{{1 45 | 46 | " # Pairs of markdown chars {{{2 47 | 48 | " Function: lh#markdown#brackets#underscore() {{{3 49 | function! lh#markdown#brackets#underscore() abort 50 | return s:Pair('_') 51 | endfunction 52 | 53 | " Function: lh#markdown#brackets#star() {{{3 54 | function! lh#markdown#brackets#star() abort 55 | if getline('.')[:col('.')-1] =~ '\s\+$' 56 | " Enumerations 57 | return '* ' 58 | else 59 | return s:Pair('*') 60 | endif 61 | endfunction 62 | 63 | " Function: s:Pair() {{{3 64 | function! s:Pair(char) abort 65 | let col = col(".") 66 | let lig = getline(line(".")) 67 | 68 | let result = a:char . '!cursorhere!' . a:char 69 | if lig[(col-2):(col-1)] == a:char . a:char 70 | return result 71 | elseif lig[col-1] == a:char 72 | let nb = matchend(lig[(col-1) :], escape(a:char, '*').'\+') 73 | return lh#map#_move_cursor_on_the_current_line(nb).lh#brackets#_jump_text(lig[(col+nb-1) :]) 74 | elseif lh#syntax#name_at(line('.'), col-1) =~ 'markdownCode' 75 | \ && lh#syntax#name_at(line('.'), col) =~ 'markdownCode' 76 | return a:char 77 | else 78 | return result.s:Mark() 79 | endif 80 | endfunction 81 | 82 | " Function: lh#markdown#brackets#backtick() {{{3 83 | function! lh#markdown#brackets#backtick() abort 84 | let col = col(".") 85 | let lig = getline(line(".")) 86 | if lig[col-2] == '$' 87 | return '`!cursorhere!`$'.s:Mark() 88 | elseif lig[col-1] == '`' 89 | let nb = matchend(lig[(col-1) :], '`\+') 90 | return lh#map#_move_cursor_on_the_current_line(nb).lh#brackets#_jump_text(lig[(col+nb-1) :]) 91 | else 92 | return '`!cursorhere!`'.s:Mark() 93 | endif 94 | endfunction 95 | 96 | " Function: lh#markdown#brackets#strike() {{{3 97 | function! lh#markdown#brackets#strike() abort 98 | let col = col(".") 99 | let lig = getline(line(".")) 100 | let lig = lig[(col-1) :] 101 | if lig =~ '' 102 | let length = len('') 103 | let lig = lig[length : ] 104 | let res = repeat("\", length) 105 | let res .= lh#brackets#_jump_text(lig) 106 | return res 107 | elseif lh#syntax#name_at(line('.'), col-1) =~ 'markdownCode' 108 | \ && lh#syntax#name_at(line('.'), col) =~ 'markdownCode' 109 | return '~' 110 | else 111 | return "!cursorhere!" . s:Mark() 112 | endif 113 | endfunction 114 | 115 | " Function: lh#markdown#brackets#match_pair() {{{3 116 | function! lh#markdown#brackets#match_pair() abort 117 | return getline(".")[col(".")-2:]=~'^\(\*\*\|__\|``\)' 118 | endfunction 119 | 120 | " Function: lh#markdown#brackets#close_math() {{{3 121 | function! lh#markdown#brackets#close_math() abort 122 | let col = col(".") 123 | let lig = getline(line(".")) 124 | 125 | let nb = 1 126 | return lh#map#_move_cursor_on_the_current_line(nb).lh#brackets#_jump_text(lig[(col+nb-1) :]) 127 | endfunction 128 | 129 | "------------------------------------------------------------------------ 130 | " ## Internal functions {{{1 131 | function! s:Mark() abort 132 | return lh#brackets#usemarks() 133 | \ ? "!mark!" 134 | \ : "" 135 | endif 136 | endfunction 137 | 138 | " }}}1 139 | "------------------------------------------------------------------------ 140 | let &cpo=s:cpo_save 141 | "============================================================================= 142 | " vim600: set fdm=marker: 143 | -------------------------------------------------------------------------------- /autoload/lh/marker.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: map-tools::lh#marker.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | let s:k_version = 360 9 | " Created: 27th Nov 2013 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " Functions to generate and handle |markers| 13 | " 14 | "------------------------------------------------------------------------ 15 | " History: 16 | " Version 2.0.2 17 | " * Moves Marker_txt() to lh#marker#txt() 18 | " TODO: «missing features» 19 | " }}}1 20 | "============================================================================= 21 | 22 | let s:cpo_save=&cpo 23 | set cpo&vim 24 | "------------------------------------------------------------------------ 25 | " ## Misc Functions {{{1 26 | " # Version {{{2 27 | function! lh#marker#version() 28 | return s:k_version 29 | endfunction 30 | 31 | " # Debug {{{2 32 | let s:verbose = get(s:, 'verbose', 0) 33 | function! lh#marker#verbose(...) 34 | if a:0 > 0 | let s:verbose = a:1 | endif 35 | return s:verbose 36 | endfunction 37 | 38 | function! s:Log(expr, ...) 39 | call call('lh#log#this',[a:expr]+a:000) 40 | endfunction 41 | 42 | function! s:Verbose(expr, ...) 43 | if s:verbose 44 | call call('s:Log',[a:expr]+a:000) 45 | endif 46 | endfunction 47 | 48 | function! lh#marker#debug(expr) abort 49 | return eval(a:expr) 50 | endfunction 51 | 52 | "------------------------------------------------------------------------ 53 | " ## Exported functions {{{1 54 | 55 | " Function: lh#marker#open() {{{2 56 | function! lh#marker#open() abort 57 | " ::call s:Verbose('lh#marker#open()') 58 | if s:Option('use_place_holders', 0) && exists('*IMAP_GetPlaceHolderStart') 59 | let m = IMAP_GetPlaceHolderStart() 60 | if !empty(m) 61 | ::call s:Verbose('lh#marker#open '.m.' using IMAP placeholder characters') 62 | return m 63 | endif 64 | endif 65 | if !exists("b:marker_open") 66 | call s:Verbose( "b:marker_open is not set") 67 | " Note: \xab <=> << 68 | call lh#marker#_set("\xab", '') 69 | ::call s:Verbose( "b:last_encoding_used is set to ".&enc) 70 | let b:last_encoding_used = &enc 71 | else 72 | if !exists('b:last_encoding_used') 73 | ::call s:Verbose( "b:last_encoding_used is not set") 74 | call lh#marker#_set(b:marker_open, b:marker_close, &enc) 75 | ::call s:Verbose( "b:last_encoding_used is set to ".&enc) 76 | let b:last_encoding_used = &enc 77 | elseif &enc != b:last_encoding_used 78 | call lh#marker#_set(b:marker_open, b:marker_close, b:last_encoding_used) 79 | ::call s:Verbose( "b:last_encoding_used is changed to ".&enc) 80 | let b:last_encoding_used = &enc 81 | endif 82 | endif 83 | ::call s:Verbose('lh#marker#open '.b:marker_open) 84 | return b:marker_open 85 | endfunction 86 | 87 | " Function: lh#marker#close() {{{2 88 | function! lh#marker#close() abort 89 | if s:Option('use_place_holders', 0) && exists('*IMAP_GetPlaceHolderEnd') 90 | let m = IMAP_GetPlaceHolderEnd() 91 | if !empty(m) 92 | ::call s:Verbose('lh#marker#close '.m.' using IMAP placeholder characters') 93 | return m 94 | endif 95 | endif 96 | if !exists("b:marker_close") 97 | ::call s:Verbose( "b:marker_close is not set") 98 | " Note: \xbb <=> >> 99 | call lh#marker#_set('', "\xbb") 100 | ::call s:Verbose( "b:last_encoding_used is set to ".&enc) 101 | let b:last_encoding_used = &enc 102 | else " if exists('b:last_encoding_used') 103 | if &enc != b:last_encoding_used 104 | ::call s:Verbose( "b:last_encoding_used is different from current") 105 | call lh#marker#_set(b:marker_open, b:marker_close, b:last_encoding_used) 106 | ::call s:Verbose( "b:last_encoding_used is changed from ".b:last_encoding_used." to ".&enc) 107 | let b:last_encoding_used = &enc 108 | endif 109 | endif 110 | ::call s:Verbose('lh#marker#close '.b:marker_close) 111 | return b:marker_close 112 | endfunction 113 | 114 | " Function: lh#marker#txt({text}) {{{2 115 | function! lh#marker#txt(...) abort 116 | return lh#marker#open() . ((a:0>0) ? a:1 : '') . lh#marker#close() 117 | endfunction 118 | 119 | " Function: lh#marker#very_magic(...) {{{3 120 | function! s:EscapeVeryMagic(text) 121 | return escape(a:text, '$.*~()|\.{}<+>') 122 | endfunction 123 | function! lh#marker#very_magic(...) abort 124 | return s:EscapeVeryMagic(lh#marker#open()) . ((a:0>0) ? a:1 : '') . s:EscapeVeryMagic(lh#marker#close()) 125 | endfunction 126 | 127 | " Function: lh#marker#is_a_marker(...) {{{3 128 | " Returns whether the text currently selected matches a marker and only one. 129 | function! lh#marker#is_a_marker(...) abort 130 | if a:0 > 0 131 | " Check whether the selected text matches a marker (and only one) 132 | return (a:1 =~ '^'.lh#marker#txt('.\{-}').'$') 133 | \ && (a:1 !~ '\%(.*'.lh#marker#close().'\)\{2}') 134 | else 135 | if line("'<") == line("'>") " I suppose markers don't spread over several lines 136 | " Extract the selected text 137 | let a = lh#visual#selection() 138 | 139 | " Check whether the selected text matches a marker (and only one) 140 | return lh#marker#is_a_marker(a) 141 | endif 142 | return 0 143 | endif 144 | endfunction 145 | 146 | "------------------------------------------------------------------------ 147 | " ## Internal functions {{{1 148 | " # Options {{{2 149 | function! s:Option(name, default) " {{{3 150 | if exists('b:'.a:name) | return b:{a:name} 151 | else | return get(g:, a:name, a:default) 152 | endif 153 | endfunction 154 | 155 | function! s:Select_or_Echo() " {{{3 156 | return get(g:, 'marker_prefers_select', 1) 157 | endfunction 158 | 159 | function! s:Select_Empty_Mark() " or delete them ? {{{3 160 | return get(g:, 'marker_select_empty_marks', 1) 161 | endfunction 162 | 163 | function! lh#marker#_set(open, close, ...) abort " {{{2 164 | if !empty(a:close) && a:close == &enc 165 | throw ":SetMarker: two arguments expected" 166 | endif 167 | let from = (a:0!=0) ? a:1 : 'latin1' 168 | " :call Dfunc('lh#marker#_set('.a:open.','.a:close.','.from.')') 169 | 170 | " let ret = '' 171 | if !empty(a:open) 172 | let b:marker_open = lh#encoding#iconv(a:open, from, &enc) 173 | " let ret = ret. " b:open=".b:marker_open 174 | endif 175 | if !empty(a:close) 176 | let b:marker_close = lh#encoding#iconv(a:close, from, &enc) 177 | " let ret = ret . " b:close=".b:marker_close 178 | endif 179 | " :call Dret("lh#marker#_set".ret) 180 | 181 | " Exploits Tom Link Stakeholders plugin if installed 182 | " http://www.vim.org/scripts/script.php?script_id=3326 183 | if exists(':StakeholdersEnable') && exists('b:marker_open') && exists('b:marker_close') 184 | let g:stakeholders#def = {'rx': b:marker_open.'\v(..{-})'.b:marker_close} 185 | " Seems to be required to update g:stakeholders#def.Replace(text) 186 | runtime autoload/stakeholders.vim 187 | endif 188 | endfunction 189 | 190 | function! lh#marker#_insert(text) range abort " {{{2 191 | " This test function is incapable of detecting the current mode. 192 | " There is no way to know when we are in insert mode. 193 | " There is no way to know if we are in visual mode or if we are in normal 194 | " mode and the cursor is on the start of the previous visual region. 195 | let mode = confirm("'< = (".line("'<").','.virtcol("'<"). 196 | \ ")\n'> =(".line("'>").','.virtcol("'>"). 197 | \ ")\n. =(".line(".").','.virtcol("."). ")\n\n Mode ?", 198 | \ "&Visual\n&Normal\n&Insert", 1) 199 | if mode == 1 200 | exe "normal gv\MarkersMark" 201 | elseif mode == 2 202 | exe "normal viw\MarkersMark" 203 | elseif mode == 3 204 | ":MI titi toto 205 | let text = lh#marker#txt(a:text) 206 | exe "normal! i".text."\l" 207 | endif 208 | endfunction 209 | 210 | function! lh#marker#_jump(param) abort " {{{2 211 | " ¿ forward([1]) or backward(0) ? 212 | let direction = get(a:param, 'direction') ? '' : 'b' 213 | let delete = get(a:param, 'delete', 0) 214 | let mode = get(a:param, 'mode') 215 | 216 | " little optimization 217 | let mo = lh#marker#open() | let emo = escape(mo, '\') 218 | let mc = lh#marker#close() | let emc = escape(mc, '\') 219 | 220 | " Save cursor and current view 221 | let position = winsaveview() 222 | 223 | " if within a marker, and going backward, {{{3 224 | if (direction == 'b') && !s:Option('marker_select_current', 0) 225 | " echomsg 'B, !C' 226 | " then: go to the start of the marker. 227 | " Principle: {{{ 228 | " 1- search backward the pair {open, close} 229 | " In order to find the current pair correctly, we must consider the 230 | " beginning of the match (\zs) to be just before the last character of 231 | " the second pair. 232 | " 2- Then, in order to be sure we did jump to a match of the open marker, 233 | " we search forward for its closing counter-part. 234 | " Test: with open='«', close = 'ééé', and the text:{{{ 235 | " blah «» 236 | " «1ééé «2ééé 237 | " «3ééé foo 238 | " «4ééé 239 | " with the cursor on any character. }}} 240 | " Without this second test, the cursor would have been moved to the end 241 | " of "blah «" which is not the beginning of a marker. 242 | " }}} 243 | if searchpair('\V'.emo, '', '\V'.substitute(emc, '.$', '\\zs\0', ''), 'b') 244 | echo '1-'.string(getpos('.')) 245 | if ! searchpair('\V'.emo, '', '\V'.emc, 'n') 246 | echo '2-'.string(getpos('.')) 247 | " restore cursor position as we are not within a marker. 248 | call winrestview(position) 249 | endif 250 | endif 251 | endif 252 | " if within a marker, and going forward, {{{3 253 | if (direction == '') && s:Option('marker_select_current_fwd', 1) 254 | " This option must be reserved to 255 | " echomsg 'F, C' 256 | " then: go to the start of the marker. 257 | if searchpair('\V'.emo, '', '\V'.emc, 'w') 258 | " echomsg '1-'.string(getpos('.')) 259 | if ! searchpair('\V'.emo, '', '\V'.emc, 'b') 260 | " echomsg '2-'.string(getpos('.')) 261 | " restore cursor position as we are not within a marker. 262 | call winrestview(position) 263 | " echomsg position 264 | else 265 | " echomsg "premature found" 266 | return s:DoSelect(emo, emc, delete, position, mode) 267 | endif 268 | endif 269 | endif 270 | " }}}3 271 | " "&ws?'w':'W'" is implicit with search() 272 | if !search('\V'.emo.'\.\{-}'.emc, direction) " {{{3 273 | " Case: No more marker 274 | " Treatment: None 275 | return "" 276 | else " found! {{{3 277 | return s:DoSelect(emo, emc, delete, position, mode) 278 | endif 279 | " }}}3 280 | endfunction 281 | 282 | function! s:DoSelect(emo, emc, delete, position, mode) abort " {{{2 283 | " In insert mode, now the mapping is using =, we need to move the cursor 284 | " one character right 285 | let mode_prefix = a:mode == 'i' ? "\\l" : '' 286 | 287 | if foldclosed('.') >= 0 288 | silent! foldopen! 289 | endif 290 | if s:Option('marker_center', 1) 291 | exe "normal! zz" 292 | endif 293 | let mark_start = virtcol('.') 294 | let select = 'v'.mark_start.'|o' 295 | if &selection == 'exclusive' | let select .= 'l' | endif 296 | let c = col('.') 297 | " search for the last character of the closing string. 298 | call search('\V'.substitute(a:emc, '.$', '\\zs\0', '')) 299 | " call confirm(matchstr(getline('.'), se). "\n".se, "&Ok", 1 ) 300 | if s:Select_or_Echo() " select! {{{4 301 | let is_not_empty = matchstr(getline('.'),'\V\%'.c.'c'.a:emo.'\zs\.\{-}\ze'.a:emc)!= '' 302 | if !a:delete && 303 | \ (s:Select_Empty_Mark() || is_not_empty) 304 | " Case: Marker containing a tag, e.g.: «tag» 305 | " Treatment: The marker is selected, going into SELECT-mode 306 | return mode_prefix.select."\" 307 | else 308 | " Case: Empty marker, i.e. not containing a tag, e.g.: «» 309 | " Treatment: The marker is deleted, going into INSERT-mode. 310 | if a:position.lnum == line('.') && a:mode == 'i' 311 | " Then we can move the cursor instead 312 | let mark_end = virtcol('.') 313 | let offset = mark_start - a:position.curswant - 1 314 | let action 315 | \ = lh#map#_move_cursor_on_the_current_line(offset) 316 | \ . repeat("\", mark_end-mark_start+1) 317 | 318 | " let g:debug = {'act':action, 'pos':a:position, 'mark_end':mark_end, 'mark_start':mark_start, 'offset':offset} 319 | call winrestview(a:position) 320 | return action 321 | endif 322 | return mode_prefix.select.'"_c' 323 | endif 324 | else " Echo! {{{4 325 | " Case: g:marker_prefers_select == 0 326 | " Treatment: Echo the tag within the marker 327 | return mode_prefix.select."v:echo lh#visual#selection()\gv\"_c" 328 | endif 329 | endfunction 330 | 331 | function! lh#marker#_move_within_marker() abort " {{{2 332 | " Purpose: move the cursor within the marker just inserted. 333 | " Here, b:marker_close exists 334 | return "\" . strlen(lh#encoding#iconv(lh#marker#close(),&enc, 'latin1')) . 'ha' 335 | endfunction 336 | 337 | function! lh#marker#_toggle_marker_in_visual() abort " {{{2 338 | " Purpose: Toggle the marker characters around a visual zone. 339 | " 1- Check wheither we areselecting a marker 340 | if line("'<") == line("'>") " I suppose markers don't spread over several lines 341 | " Extract the selected text 342 | let a_save = @a 343 | normal! gv"ay 344 | let a = @a 345 | let @a = a_save 346 | 347 | " Check whether the selected text is strictly a marker (and only one) 348 | if (a =~ '^'.lh#marker#txt('.\{-}').'$') 349 | \ && (a !~ '\%(.*'.lh#marker#close().'\)\{2}') 350 | " 2- If so, strip the marker characters 351 | let a = substitute(a, lh#marker#txt('\(.\{-}\)'), '\1', '') 352 | let unnamed_save=@" 353 | exe "normal! gvs".a."\" 354 | " escape(a, '\') must not be used. 355 | " exe "normal! gvs".a."\v".(strlen(a)-1)."ho\" 356 | let @"=unnamed_save 357 | return 'a' 358 | endif 359 | endif 360 | 361 | " 3- Else insert the pair of marker characters around the visual selection 362 | call lh#map#insert_around_visual(lh#marker#open(),lh#marker#close(),0,0) 363 | return '`>'.lh#encoding#strlen(lh#marker#txt()).'l' 364 | endfunction 365 | 366 | " }}}1 367 | "------------------------------------------------------------------------ 368 | let &cpo=s:cpo_save 369 | "============================================================================= 370 | " vim600: set fdm=marker: 371 | -------------------------------------------------------------------------------- /autoload/lh/vim/brackets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/brackets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | " Created: 20th Mar 2008 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Functions that tune how some bracket characters should expand in VimL 12 | " }}}1 13 | "============================================================================= 14 | 15 | "------------------------------------------------------------------------ 16 | let s:cpo_save=&cpo 17 | set cpo&vim 18 | "------------------------------------------------------------------------ 19 | " ## Misc Functions {{{1 20 | " # Version {{{2 21 | function! lh#vim#brackets#version() 22 | return s:k_version 23 | endfunction 24 | 25 | " # Debug {{{2 26 | let s:verbose = get(s:, 'verbose', 0) 27 | function! lh#vim#brackets#verbose(...) 28 | if a:0 > 0 | let s:verbose = a:1 | endif 29 | return s:verbose 30 | endfunction 31 | 32 | function! s:Log(expr, ...) abort 33 | call call('lh#log#this',[a:expr]+a:000) 34 | endfunction 35 | 36 | function! s:Verbose(expr, ...) abort 37 | if s:verbose 38 | call call('s:Log',[a:expr]+a:000) 39 | endif 40 | endfunction 41 | 42 | function! lh#vim#brackets#debug(expr) abort 43 | return eval(a:expr) 44 | endfunction 45 | 46 | "------------------------------------------------------------------------ 47 | " ## API {{{1 48 | " Inserts '<>' on '<', except after an if or within comment. {{{2 49 | " This rule knows an exception : within a string, or after a '\', '<' is 50 | " always converted to '<>'. 51 | " Does not handle special characters like ''<' and ''>' 52 | " Updated on 08th May 2004 53 | function! lh#vim#brackets#lt() abort 54 | let l = getline('.') 55 | let c = col('.') - 1 56 | let syn = synIDattr(synID(line('.'),c,1),'name') 57 | if (l[c-1] != '\') && (syn !~? '\(string\)\|\(character\)') 58 | if (syn =~? 'comment') || (l =~ '\v.*<(if|elseif|while|let\s+\S+|AssertBuf|SetBuf)\s*.*') 59 | return '<' 60 | endif 61 | endif 62 | if lh#brackets#usemarks() 63 | return '!mark!' 64 | else 65 | return '' 66 | endif 67 | endfunction 68 | 69 | " Inserts '""' on '"', except for comments {{{2 70 | " (supposed equivalent to empty lines) 71 | " Heuristic used: 72 | " - before a '"', 73 | " - within a vimString => likely a string to close => move 74 | " - insert "|" 75 | " - after ')', it can not be a string => comment 76 | " - in the beginning of a line ('^\s*$') => comment 77 | " - otherwise => string 78 | function! lh#vim#brackets#dquotes() abort 79 | " TEST: OK sans imaps.vim 80 | let line = getline(line('.')) 81 | let col = col('.')-1 82 | let l = strpart(line, 0, col) 83 | if line[col] == '"' 84 | call s:Verbose('match_at(%1, %2) : %3', line('.'), col, map(synstack(line('.'), col), 'synIDattr(v:val, "name")')) 85 | if lh#syntax#match_at('vimString', line('.'), col) 86 | return lh#brackets#_jump() 87 | else 88 | " Insert a string before another string 89 | return '"!cursorhere!"!mark!.' 90 | endif 91 | elseif l =~ '\m)\s*$\|^\s*$' 92 | return '"' 93 | elseif lh#brackets#usemarks() 94 | return '"!cursorhere!"!mark!' 95 | else 96 | return '""'. lh#map#_move_cursor_on_the_current_line(-1) 97 | endif 98 | endfunction 99 | "------------------------------------------------------------------------ 100 | let &cpo=s:cpo_save 101 | "============================================================================= 102 | " vim600: set fdm=marker: 103 | -------------------------------------------------------------------------------- /doc/default_brackets.md: -------------------------------------------------------------------------------- 1 | ## Default bracket mappings 2 | 3 | By default, lh-brackets comes with a few ready-to-use mappings: 4 | * some are [global](#global-mappings) and apply to all filetypes, 5 | * other are specialized for various filetypes: 6 | * [C and C++](#c-and-c-mappings) 7 | * [HTML](#html-mappings) 8 | * [Javascript](#javascript-mappings) 9 | * [Markdown](#markdown-mappings) 10 | * [Perl](#perl-mappings) 11 | * [Ruby](#ruby-mappings) 12 | * [(La)TeX](#latex-mappings) 13 | * [VimL](#viml-mappings) 14 | 15 | The default mappings can be inhibited with the options 16 | `(bpg):cb_no_default_brackets`, `g:cb_enable_default` and 17 | `g:cb_disable_default`. See `:h :Brackets-default`. 18 | 19 | ### Global mappings 20 | 21 | The following mappings apply to all filetypes (unless specified otherwise, or specialized). 22 | 23 | | in mode | insert | visual | normal | 24 | |:------------------------|:----------------------------|:----------------------------------------------|:--------------------------| 25 | | **keys** | expands into .. | surrounds the selection with ... 2 | surrounds the current ... | 26 | | `(` | `()«»` | `()` | word | 27 | | `[` | `[]«»` | 1 | 1 | 28 | | `[` | | `[]` | word | 29 | | `{` | `{}«»`3 | `{}` | word | 30 | | `{` | | `{\n\n}«»` | line | 31 | | `"` (1 double quote) | `""«»` | 1 | 1 | 32 | | `""` | | `""` | word | 33 | | `'` | `''«»`4 | 1 | 1 | 34 | | `''` (2 single quotes) | | `''` | word | 35 | | `<` | | `<>` | word | 36 | 37 | #### Notes: 38 | * 1 Not defined to avoid hijacking default vim key bindings. 39 | * 2 The visual mode mappings do not surround the current marker/placeholder selected, but trigger the INSERT-mode mappings instead. 40 | * 3 No newline is inserted by default. However, hitting `` in the middle of a pair of curly-brackets will expand into `{\n\n}`. 41 | * 4 This mapping is neutralized for text filetypes -- the list of text-filetypes is defined in [`lh#ft#is_text()`](http://github.com/LucHermitte/lh-vim-lib) 42 | * `«»` represents a marker/placeholder, it may be expanded with other characters like `<++>` depending on your preferences. 43 | * These mappings can be disabled from the `.vimrc` by setting `g:cb_no_default_brackets` to 1 (default: 0) 44 | 45 | ### C and C++ mappings 46 | 47 | See [lh-cpp documentation](https://github.com/LucHermitte/lh-cpp#brackets) for the complete mappings table. 48 | 49 | The main differences from the global table are: 50 | * `}` jumps to the next non whitespace/newline character that is a `}` if 51 | `g:cb_jump_over_newlines` equals to 1 (default case). If you want to jump 52 | after the `}` only if it's exactly right after the cursor, then set 53 | `g:cb_jump_over_newlines` to 0 in your `.vimrc`. See #26. 54 | When not jumping, `}` is simply inserted. 55 | 56 | * In visual mode, `{` surrounds the selection with a pair of 57 | curly brackets (and newlines are introduced). 58 | * `` is recognized as an opening bracket (I use it a lot to write Doxygen 59 | _code_ instead of `\c` when I need to type several things). 60 | * `;` will try to close parenthesis -- set `(bpg):[{ft}_]semicolon_closes_bracket` to 0 to inhibit this setting. 61 | * `` take care of semi-colons after the closing curly-bracket -- set `(bpg):[{ft}_]semicolon_closes_bracket` to 0 to inhibit this setting. 62 | 63 | | in mode | insert | 64 | | :--------------------------------------------------------------------- | :---------------- | 65 | | **keys** | expands into .. | 66 | | `<` after `#include`, `template`, `typename`, `_cast` or standard types | `<>;` | 67 | | `{` after `struct`, `class`, `enum` or `union` | `{};` | 68 | | `[` after a `[` | `[[]]«»` | 69 | | `]` before `]]` | close all `]]` | 70 | 71 | #### Notes 72 | * For `<` to expand into `<|>` after standard types like `std::vector`, [lh-cpp](https://github.com/LucHermitte/lh-cpp) 73 | v2.2.1+ is required 74 | 75 | ### HTML mappings 76 | 77 | The main differences from the global table are: 78 | * Typing `<` twice results in `<`, and `<>` results in `>`. 79 | * In visual mode, `<` surrounds the selection with a pair of 80 | angle brackets. 81 | 82 | ### Javascript mappings 83 | The main differences from the global table are: 84 | * In visual mode, `{` surrounds the selection with a pair of 85 | curly brackets (and newlines are introduced). 86 | 87 | ### Markdown mappings 88 | New mappings are avaible. 89 | 90 | | in mode | insert | visual | normal | 91 | |:------------------------|:---------------------------------|:----------------------------------------------|:--------------------------| 92 | | **keys** | expands into .. | surrounds the selection with ... 2 | surrounds the current ... | 93 | | `_` | `__<++>` 3 | `__` | word | 94 | | `_` after a `_` | `____<++>` | n/a | n/a | 95 | | `*` | `**<++>` 3,4 | `**` | word | 96 | | `*` after a `*` | `****<++>` | n/a | n/a | 97 | | `` ` `` | `` ``<++>`` 5 | `` `` `` | word | 98 | | `~` | `«»` | 1 | 1 | 99 | | `~` | | `` | word | 100 | 101 | #### Notes: 102 | * 1 Not defined to avoid hijacking default vim key bindings. 103 | * 2 The visual mode mappings do not surround the current marker/placeholder selected, but trigger the INSERT-mode mappings instead. 104 | * 3 Within a pair of backquotes (_code_ marker), formatting pairs 105 | are not expanded 106 | * 4 Right after spaces at the beginning of the line, `*` is not 107 | expanded: it will serve to start a new point in a bullet-list. 108 | * 5 When type after a dollar sign, backtick will get expanded into `` $``$<++>``, and `$` will move the cursor and consume any placeholder if typed between and backtick and an existing dollar. 109 | 110 | ### Perl mappings 111 | The main differences from the global table are: 112 | * In visual mode, `{` surrounds the selection with a pair of 113 | curly brackets (and newlines are introduced). 114 | * In visual mode, `<` surrounds the selection with a pair of 115 | angle brackets. 116 | 117 | ### Ruby mappings 118 | * In normal mode, `{` replace `begin`-`end` block by `{-}`, or the other 119 | way around. 120 | 121 | ### (La)TeX mappings 122 | New and specialized mappings are avaible. 123 | 124 | | in mode | insert | visual | normal | 125 | |:------------------------|:----------------------------|:----------------------------------------------|:--------------------------| 126 | | **keys** | expands into .. | surrounds the selection with ... 2 | surrounds the current ... | 127 | | `(` | `()<++>` | `()` | word | 128 | | `(` after a `\` | `\(\)<++>` | n/a | n/a | 129 | | `{` | `{}<++>` | `{}` | word | 130 | | `{` after a `\` | `\{\}<++>` | n/a | n/a | 131 | | `[` | `[]<++>` | `[]` | word | 132 | | `[` after a `\` | `\[\]<++>` | n/a | n/a | 133 | | `[` | | `[]` | word | 134 | | `$` | `$$<++>` | 1 | 1 | 135 | | `$` | | `$$` | word | 136 | 137 | #### Notes: 138 | * 1 Not defined to avoid hijacking default vim key bindings. 139 | * 2 The visual mode mappings do not surround the current marker/placeholder selected, but trigger the INSERT-mode mappings instead. 140 | * In (La)TeX, `<++>` is used as a placeholder instead of `«»`. 141 | 142 | ### VimL mappings 143 | 144 | New and specialized mappings are avaible. 145 | 146 | | in mode | insert | visual | normal | 147 | |:------------------------|:----------------------------|:----------------------------------------------|:--------------------------| 148 | | **keys** | expands into .. | surrounds the selection with ... 2 | surrounds the current ... | 149 | | `(` | `()«»` | `()` | word | 150 | | `(` after a `\` | `\(\)«»` | n/a | n/a | 151 | | `<` | `<>«»` 5 | 1 | 1 | 152 | | `<` | | `<>` | word | 153 | | `"` | `""«»` 6 | 1 | 1 | 154 | 155 | #### Notes: 156 | * 1 Not defined to avoid hijacking default vim key bindings. 157 | * 2 The visual mode mappings do not surround the current marker/placeholder selected, but trigger the INSERT-mode mappings instead. 158 | * 5 except after an `if`, a `while`, or within comments. Still 159 | this rule knowns an exception: within a string, or after a `\`, `<` is 160 | always converted to `<>`. Does not handle special characters like `'<` and 161 | `'>` 162 | * 6 except for comments, and special attention is given when the 163 | cursor is within strings 164 | -------------------------------------------------------------------------------- /doc/lh-map-tools.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/lh-brackets/40af9b67424003a03e8384eab81256bfe535db0b/doc/lh-map-tools.txt -------------------------------------------------------------------------------- /ftplugin/python/python_snippets.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: ftplugin/python/python_snippets.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.5.4 8 | let s:k_version = '3.5.4' 9 | " Created: 21st Jan 2015 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " Snippets of python Control Statements 13 | " 14 | "------------------------------------------------------------------------ 15 | " TODO: 16 | " - move this file from lh-brachets to lh-misc (or a future lh-python in case I 17 | " spend more time writing Python) 18 | " }}}1 19 | "============================================================================= 20 | 21 | " Buffer-local Definitions {{{1 22 | " Avoid local reinclusion {{{2 23 | if &cp || (exists("b:loaded_ftplug_python_snippets") 24 | \ && (b:loaded_ftplug_python_snippets >= s:k_version) 25 | \ && !exists('g:force_reload_ftplug_python_snippets')) 26 | finish 27 | endif 28 | let b:loaded_ftplug_python_snippets = s:k_version 29 | let s:cpo_save=&cpo 30 | set cpo&vim 31 | " Avoid local reinclusion }}}2 32 | 33 | "------------------------------------------------------------------------ 34 | " Local mappings {{{2 35 | 36 | " Control statements {{{3 37 | " --- if ---------------------------------------------------------{{{4 38 | "--if insert "if" statement {{{5 39 | Inoreabbr if =PyMapOnSingleLine('if ', 40 | \ "\\if !cursorhere!:\n!mark!") 41 | "--,if insert "if" statement 42 | xnoremap if 43 | \ @=lh#map#surround('if !cursorhere!:', '!mark!', 44 | \ 1, 1, '', 1, 'if ') 45 | xnoremap if 46 | \ @=lh#map#surround('if ', "!cursorhere!:\n!mark!", 47 | \ 0, 1, '', 1, 'if ') 48 | nmap if Vif 49 | nmap if ^v$if 50 | 51 | "--elif insert "elif" statement {{{5 52 | Inoreabbr elif =PyMapOnSingleLine('elif ', 53 | \ "\\elif !cursorhere!:\n!mark!") 54 | "--,elif insert "elif" statement 55 | xnoremap elif 56 | \ @=lh#map#surround('elif !cursorhere!:', '!mark!', 57 | \ 1, 1, '', 1, 'elif ') 58 | xnoremap elif 59 | \ @=lh#map#surround('elif ', "!cursorhere!:\n!mark!", 60 | \ 0, 1, '', 1, 'elif ') 61 | nmap elif Velif 62 | nmap elif ^v$elif 63 | 64 | "--elif insert "elif" statement {{{5 65 | Inoreabbr else =PyMapOnSingleLine('else ', 66 | \ "\\else:\n") 67 | "--,elif insert "elif" statement 68 | xnoremap else 69 | \ @=lh#map#surround('else:!cursorhere!', '\!mark!', 70 | \ 1, 1, '', 1, 'else ') 71 | nmap else Velse 72 | 73 | " --- for --------------------------------------------------------{{{4 74 | "--for insert "for" statement {{{5 75 | Inoreabbr for =PyMapOnSingleLine('for ', 76 | \ "\\for !cursorhere!:\n!mark!") 77 | "--,for insert "for" statement 78 | xnoremap for 79 | \ @=lh#map#surround('for !cursorhere!:', '!mark!', 80 | \ 1, 1, '', 1, 'for ') 81 | xnoremap for 82 | \ @=lh#map#surround('for ', "!cursorhere!:\n!mark!", 83 | \ 0, 1, '', 1, 'for ') 84 | nmap for Vfor 85 | nmap for ^v$for 86 | 87 | " --- while ------------------------------------------------------{{{4 88 | "--while insert "while" statement {{{5 89 | Inoreabbr while =PyMapOnSingleLine('while ', 90 | \ "\\while !cursorhere!:\n!mark!") 91 | "--,while insert "while" statement 92 | xnoremap while 93 | \ @=lh#map#surround('while !cursorhere!:', '!mark!', 94 | \ 1, 1, '', 1, 'while ') 95 | xnoremap while 96 | \ @=lh#map#surround('while ', "!cursorhere!:\n!mark!", 97 | \ 0, 1, '', 1, 'while ') 98 | nmap while Vwhile 99 | nmap while ^v$while 100 | 101 | "============================================================================= 102 | " Global Definitions {{{1 103 | " Avoid global reinclusion {{{2 104 | if &cp || (exists("g:loaded_ftplug_python_snippets") 105 | \ && (g:loaded_ftplug_python_snippets >= s:k_version) 106 | \ && !exists('g:force_reload_ftplug_python_snippets')) 107 | let &cpo=s:cpo_save 108 | finish 109 | endif 110 | let g:loaded_ftplug_python_snippets = s:k_version 111 | " Avoid global reinclusion }}}2 112 | "------------------------------------------------------------------------ 113 | " Functions {{{2 114 | " Note: most filetype-global functions are best placed into 115 | " autoload/«your-initials»/python/«python_snippets».vim 116 | " Keep here only the functions are are required when the ftplugin is 117 | " loaded, like functions that help building a vim-menu for this 118 | " ftplugin. 119 | 120 | " Function: PyMapOnSingleLine(key, what) {{{3 121 | function! PyMapOnSingleLine(key, what) abort 122 | let c = col('.') - 1 123 | let l = getline('.') 124 | let after = strpart(l, c) 125 | let before = strpart(l, 0, c) 126 | " let g:msg = c.' --> <' . before . '> ## <'.after . '>' 127 | " echomsg g:msg 128 | if before =~ '^\s*$' 129 | if after =~ '^\s*$' 130 | return lh#map#insert_seq(a:key, a:what) 131 | else " => surround condition 132 | let ll = lh#leader#get_local() 133 | exe "normal ".ll.ll.a:key 134 | return "" 135 | endif 136 | else 137 | return a:key 138 | endif 139 | endfunction 140 | 141 | " }}}1 142 | "------------------------------------------------------------------------ 143 | let &cpo=s:cpo_save 144 | "============================================================================= 145 | " vim600: set fdm=marker: 146 | -------------------------------------------------------------------------------- /mkVba/mk-lh-map-tools.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: mkvba/mk-lh-map-tools.vim 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | let s:version = '3.6.0' 9 | " Created: 06th Nov 2007 10 | " Last Update: 16th Nov 2019 11 | "------------------------------------------------------------------------ 12 | cd :p:h 13 | try 14 | let save_rtp = &rtp 15 | let &rtp = expand(':p:h:h').','.&rtp 16 | exe '23,$MkVimball! lh-map-tools-'.s:version 17 | set modifiable 18 | set buftype= 19 | finally 20 | let &rtp = save_rtp 21 | endtry 22 | finish 23 | README.md 24 | addon-info.txt 25 | after/ftplugin/c/c_brackets.vim 26 | after/ftplugin/html/html_brackets.vim 27 | after/ftplugin/javascript_brackets.vim 28 | after/ftplugin/markdown-brackets.vim 29 | after/ftplugin/perl/perl_brackets.vim 30 | after/ftplugin/ruby/ruby_brackets.vim 31 | after/ftplugin/tex/tex_brackets.vim 32 | after/ftplugin/vim/vim_brackets.vim 33 | autoload/lh/brackets.vim 34 | autoload/lh/cpp/brackets.vim 35 | autoload/lh/html/brackets.vim 36 | autoload/lh/map.vim 37 | autoload/lh/markdown/brackets.vim 38 | autoload/lh/marker.vim 39 | autoload/lh/vim/brackets.vim 40 | doc/default_brackets.md 41 | doc/lh-map-tools.txt 42 | ftplugin/python/python_snippets.vim 43 | mkVba/mk-lh-map-tools.vim 44 | plugin/bracketing.base.vim 45 | plugin/common_brackets.vim 46 | plugin/misc_map.vim 47 | tests/lh/test-split.vim 48 | tests/lh/test-functions.vim 49 | VimFlavor 50 | -------------------------------------------------------------------------------- /plugin/bracketing.base.vim: -------------------------------------------------------------------------------- 1 | " ====================================================================== 2 | " File: plugin/bracketing.base.vim 3 | " Author: Luc Hermitte 4 | " 5 | " License: GPLv3 with exceptions 6 | " 7 | " Version: 3.6.0 8 | " 9 | " Stephen Riehm's braketing macros for vim 10 | " Customizations by Luc Hermitte. 11 | " ====================================================================== 12 | " History: {{{1 13 | " 05th Jan 2021: by LH 14 | " * Move functions into autoload plugin 15 | " 12th Sep 2018: by LH 16 | " * Provide default mappings for terminal mode 17 | " 24th May 2018: by LH 18 | " * Avoid remapping in v_MarkersCloseAllAndJumpToLast 19 | " * Fix `v_MarkersCloseAllAndJumpToLast` 20 | " 08th Nov 2016: by LH 21 | " * Add MarkersJumpOutside 22 | " 10th Dec 2015: by LH 23 | " * !mark! & co have been deprecated as mappings 24 | " * Support for closing all markers and jumping to the last one 25 | " 20th Mar 2012: by LH 26 | " * lh-cpp-> GPLv3 27 | " 03rd Jan 2011: by LH 28 | " * marker_prefers_select=0 fixed 29 | " 25th Nov 2010: by LH 30 | " * Aware of Tom Link's Stakeholders presence for :SetMarker 31 | " 20th Mar 2008: by LH 32 | " * Defect #1 : It is possible to configure the colour used to 33 | " highlight the marker 34 | " 22nd Feb 2008: by LH 35 | " * :SetMarker could accept one argument 36 | " 15th Feb 2008 by LH 37 | " * g:marker_select_current_fwd to select the current marker when 38 | " the cursor on anywhere on it (but the last character) 39 | " 25th May 2006 by LH 40 | " * Workaround for UTF-8. 41 | " Never defined a !imapping! as a call to a script-local 42 | " function. Only global functions can be used in UTF-8. 43 | " 22nd Nov 2004 by LH 44 | " * New behaviour for !mark! in visual mode: 45 | " If a marker is selected (in visual or select mode), then the 46 | " marker is replaced by its contents, and we end in insert 47 | " mode, just after the contents. 48 | " e.g. "<+contents+>" becomes "contents" 49 | " Otherwise, the visual selection is wrapped into a pair of 50 | " marker characters. 51 | " * New mappings: !mark! and MarkersMark has been added for 52 | " the normal mode. 53 | " * Revert to g:loaded_bracketing_base 54 | " 23rd May 2004 by LH 55 | " * Use s:loaded_bracketing_base instead of 56 | " g:loaded_bracketing_base 57 | " 17th Sep 2003 by LH 58 | " * Marker_Jump() works correctly even if 'selection' is set to 59 | " exclusive. 60 | " 25th Aug 2003 by LH 61 | " * And 2 new mappingS: !jump-and-del! !bjump-and-del! which 62 | " always delete the marker. Useful to always have the same 63 | " behaviour when programming (ft)plugins. 64 | " 15th Aug 2003 by LH, from an idea of Christophe "CLeek" Sahut 65 | " * New option: [bg]:marker_center used to center the display 66 | " area on the marker we have jumped to. 67 | " 25th Jun 2003 by LH 68 | " * Small correction when b:Marker_Open is set 69 | " 09th jan 2003 by LH 70 | " * The :vmap for jumping backward uses: "`>" (Srinath's idea) 71 | " * Add option [bg]:marker_select_current. 72 | " 07th jan 2003 by LH 73 | " * Changes go into black hole register -> '"_c' -> '@"' is left 74 | " unchanged. 75 | " * Doesn't mess any more the search history ; but the tag 76 | " within a marker is not supposed to spread accross several 77 | " lines -- I think it is a reasonable requirement. 78 | " * The marker string may contain escape characters 79 | " * Insensible to 'magic' 80 | " * The marker string is automatically converted according to 81 | " the current encoding -- may work only between latin1 and 82 | " utf-8 because of iconv(). 83 | " * Going into normal mode with instead of 84 | " '' -> less screen flashes 85 | " * Little bug fixed with :foldopen 86 | " 10th dec 2002 by LH 87 | " * Add compatibility with vim-latex::imaps.vim 88 | " 09th dec 2002 by LH 89 | " * First steps to support encodings different than latin1 90 | " - ¡...! mappings changed to !...! 91 | " - using nr2char(char2nr("\xab")) 92 | " * Name of the mappings changed 93 | " 20th nov 2002 by LH 94 | " * Don't mess with folding 95 | " 08th nov 2002 by LH 96 | " * Pure vim6 solution. 97 | " * s/brkt/marker in options and functions names. 98 | " * Support closing markers of several characters. 99 | " * New mapping to jump to the previous marker 100 | " * Two commands: :MN and :MP that work in normal, visual and 101 | " insert modes and permit to jump to next/previous marker. 102 | " 21st jul 2002 by LH 103 | " * e-mail address obfuscated for spammers 104 | " 04th apr 2002 by LH 105 | " * Marker_Txt takes an optional parameter : the text 106 | " 21st feb 2002 by LH 107 | " * When a comment is within a mark, we now have the possibility 108 | " to select the mark (in Select-MODE ...) instead of echoing 109 | " the comment. 110 | " * In this mode, an empty mark can be chosen or deleted. 111 | " Previous Version: ?????? by LH 112 | " * Use accessors to acces b:marker_open and b:marker_close. 113 | " Reason: Changing buffers with VIM6 does not re-source this 114 | " file. 115 | " Previous Version: 22nd sep 2001 by LH 116 | " * Delete all the settings that should depends on ftplugins 117 | " * Enable to use other markers set as a buffer-relative option. 118 | " Based On Version: 16.01.2000 119 | " (C)opyleft: Stephen Riehm 1991 - 2000 120 | " 121 | " Needs: * VIM 6.0 + 122 | " * misc_map.vim (MapAroundVisualLines, by LH) 123 | " 124 | " Credits: 125 | " Stephen Riehm, Benji Fisher, Gergely Kontra, Robert Kelly IV. 126 | " 127 | "------------------------------------------------------------------------ 128 | " Options: {{{1 129 | " b:marker_open -> the characters that opens the marker ; default '«' 130 | " b:marker_close -> the characters that closes the marker ; default '»' 131 | " They are buffer-relative in order to be assigned to different values 132 | " regarding the filetype of the current buffer ; e.g. '«»' is not an 133 | " appropriate marker with LaTeX files. 134 | " 135 | " g:marker_prefers_select ; default 1 136 | " Option to determine if the comment within a marker should be echoed or 137 | " if the whole marker should be selected (select-mode). 138 | " Beware: The select-mode is considered to be a visual-mode. Hence all 139 | " the i*map won't expand in select-mode! i*abbr fortunately does. 140 | " 141 | " g:marker_select_empty_marks ; default 1 142 | " Option to determine if an empty marker should be selected or deleted. 143 | " Works only if g:marker_prefers_select is set. 144 | " 145 | " [bg]:use_place_holders ; default 0 146 | " Option that says the characters to use are [bg]:Imap_PlaceHolderStart 147 | " and [bg]:Imap_PlaceHolderEnd. 148 | " These characters are the ones used by Srinath Avadhanula's imaps.vim 149 | " I meant to support Srinath's variations on my own variations ; this 150 | " way, this script defines correct and advanced jumping functions for 151 | " the vim-latex suite. 152 | " 153 | " [bg]:marker_select_current ; default 0 154 | " When this option is set to 1, the 'jump backward' mecanism will 155 | " select the current marker (the cursor is within) if applicable. 156 | " Otherwise, we jump to the marker before the one the cursor is within. 157 | " 158 | " [bg]:marker_center ; default 1 159 | " When this option is set to 1, the line of the marker (we jump to) is 160 | " moved to the middle of the window. 161 | " 162 | "------------------------------------------------------------------------ 163 | " }}}1 164 | " =========================================================================== 165 | " scriptencoding latin1 166 | " Settings {{{1 167 | " ======== 168 | " These settings are required for the macros to work. 169 | " Essentially all you need is to tell vim not to be vi compatible, 170 | " and to do some kind of groovy autoindenting. 171 | " 172 | " Tell vim not to do screwy things when searching 173 | " (This is the default value, without c) 174 | "set cpoptions=BeFs 175 | set cpoptions-=c 176 | " Avoid reinclusion 177 | if exists("g:loaded_bracketing_base") && !exists('g:force_reload_bracketing_base') 178 | finish 179 | endif 180 | let g:loaded_bracketing_base = 360 181 | 182 | let s:cpo_save = &cpo 183 | set cpo&vim 184 | 185 | " Mappings that can be redefined {{{1 186 | " ============================== 187 | " (LH) As I use a lot, I use different keys than those proposed by SR. 188 | if get(g:, 'marker_define_jump_mappings', 1) 189 | if has('gui_running') 190 | call lh#mapping#plug('', 'MarkersMark', 'inv') 191 | call lh#mapping#plug('', 'MarkersJumpF', 'inv') 192 | call lh#mapping#plug('', 'MarkersJumpB', 'inv') 193 | call lh#mapping#plug('', 'MarkersCloseAllAndJumpToLast', 'inv') 194 | call lh#mapping#plug('', 'MarkersJumpOutside', 'insx') 195 | else 196 | call lh#mapping#plug('', 'MarkersMark', 'inv') 197 | call lh#mapping#plug('', 'MarkersJumpF', 'inv') 198 | call lh#mapping#plug('', 'MarkersJumpB', 'inv') 199 | call lh#mapping#plug('$', 'MarkersCloseAllAndJumpToLast', 'inv') 200 | call lh#mapping#plug('', 'MarkersJumpOutside', 'insx') 201 | endif 202 | endif 203 | 204 | inoremap MarkersInsertMark =lh#marker#txt() 205 | imap MarkersMark MarkersInsertMark=lh#marker#_move_within_marker() 206 | vnoremap MarkersMark @=lh#marker#_toggle_marker_in_visual() 207 | nmap MarkersMark viwMarkersMark 208 | 209 | " is like '', but without any screen flash. Here, we unselect 210 | " the current selection and go into normal mode. 211 | vnoremap MarkersJumpF @=lh#marker#_jump({'direction':1, 'mode':'v'}) 212 | inoremap MarkersJumpF =lh#marker#_jump({'direction':1, 'mode':'i'}) 213 | nnoremap MarkersJumpF @=lh#marker#_jump({'direction':1, 'mode':'n'}) 214 | vnoremap MarkersJumpB `<@=lh#marker#_jump({'direction':0, 'mode':'v'}) 215 | nnoremap MarkersJumpB @=lh#marker#_jump({'direction':0, 'mode':'n'}) 216 | inoremap MarkersJumpB =lh#marker#_jump({'direction':0, 'mode':'i'}) 217 | 218 | vnoremap MarkersJumpAndDelF @=lh#marker#_jump({'direction':1, 'mode':'v', 'delete':1}) 219 | nnoremap MarkersJumpAndDelF @=lh#marker#_jump({'direction':1, 'mode':'n', 'delete':1}) 220 | imap MarkersJumpAndDelF MarkersJumpFAndDel 221 | vnoremap MarkersJumpAndDelB @=lh#marker#_jump({'direction':0, 'mode':'v', 'delete':1}) 222 | nnoremap MarkersJumpAndDelB @=lh#marker#_jump({'direction':0, 'mode':'n', 'delete':1}) 223 | imap MarkersJumpAndDelB MarkersJumpFAndDel 224 | 225 | nnoremap MarkersCloseAllAndJumpToLast a=lh#brackets#close_all_and_jump_to_last_on_line(lh#brackets#closing_chars(), {}) 226 | vnoremap MarkersCloseAllAndJumpToLast `=lh#brackets#close_all_and_jump_to_last_on_line(lh#brackets#closing_chars(), {'mode': 'v'}) 227 | imap MarkersCloseAllAndJumpToLast =lh#brackets#close_all_and_jump_to_last_on_line(lh#brackets#closing_chars(), {}) 228 | 229 | inoremap MarkersJumpOutside =lh#brackets#jump_outside({'mode': 'i'}) 230 | nnoremap MarkersJumpOutside @=lh#brackets#jump_outside({'mode': 'n'}) 231 | xnoremap MarkersJumpOutside @=lh#brackets#jump_outside({'mode': 'x'}) 232 | smap MarkersJumpOutside aMarkersJumpOutside 233 | 234 | " Note: don't add "