Skip to content

Commit

Permalink
Fix <CR> mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonwoodland committed Jul 30, 2022
0 parents commit e1a9bc9
Show file tree
Hide file tree
Showing 12 changed files with 557 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
vendor
doc/tags
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
language: ruby
script: make test
19 changes: 19 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## v0.2.0
> Sep 28, 2015
* JavaScript: add semicolons in the file when `'use strict';` is found.

## v0.1.2
> Jun 19, 2015
* Hotfix to actually make the last version's change work.

## v0.1.1
> Jun 19, 2015
* Prevent semicolons in if/else in JavaScript.

## v0.1.0
> Jun 3, 2015
* Initial release.
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2015 Rico Sta. Cruz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
31 changes: 31 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
vim := vim

test: test-plain test-endwise

test-plain: vendor/vimrc
@echo env HOME="$(shell pwd)/vendor" ${vim} -Nu $< +"Vader! test/*"

test-endwise: vendor/vimrc
@env test_endwise=1 HOME="$(shell pwd)/vendor" ${vim} -Nu $< +"Vader! test/endwise/* test/*"

vim: vendor/vimrc
@env HOME="$(shell pwd)/vendor" ${vim} -Nu $<

vendor/vimrc: vendor/vader.vim vendor/vim-endwise
@mkdir -p ./vendor
@echo "filetype off" > $@
@echo "set rtp+=vendor/vader.vim" >> $@
@echo "set rtp+=vendor/vim-endwise" >> $@
@echo "set rtp+=." >> $@
@echo "filetype plugin indent on" >> $@
@echo "syntax enable" >> $@

vendor/vader.vim:
@mkdir -p ./vendor
@git clone https://github.com/junegunn/vader.vim.git ./vendor/vader.vim

vendor/vim-endwise:
@mkdir -p ./vendor
@git clone https://github.com/tpope/vim-endwise.git ./vendor/vim-endwise

.PHONY: test vendor/vimrc doc
90 changes: 90 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# vim-closer

**Closes brackets.** Perfect companion to [vim-endwise]. Basically, a more conservative version of [auto-pairs] that only works when you press Enter.

> NB: This plugin is known to have issues when used with COQ.nvim. See [#37](https://github.com/rstacruz/vim-closer/issues/37).
----

![](https://raw.githubusercontent.com/rstacruz/vim-closer/gh-pages/closer.gif)

----

[![Status](http://img.shields.io/travis/rstacruz/vim-closer/master.svg)](https://travis-ci.org/rstacruz/vim-closer/ "See test builds")

[auto-pairs]: https://github.com/jiangmiao/auto-pairs
[vim-endwise]: https://github.com/tpope/vim-endwise

<br>

## What

Closings are automatically inserted after pressing <kbd>Enter ⏎</kbd>. It supports languages that have `(`, `[`, and `{` brackets.

```css
.section {⏎
```

```css
.section {
|
}
```

It tries to automatically figure out whatever braces were opened in the line. This is useful for, say, JavaScript where `});` is commonly seen.

```js
describe('test', function () {⏎
```
```js
describe('test', function () {
|
})
```
Semicolons are automatically added if it makes sense, and only if another line in the buffer ends in `;`.
```js
var x = 1;
setImmediate(function () {⏎
```
```js
var x = 1;
setImmediate(function () {
|
});
```
<br>
## Install
When using [vim-plug], add this to your `~/.vimrc`:
[vim-plug]: https://github.com/junegunn/vim-plug
```vim
Plug 'rstacruz/vim-closer'
```
<br>
## By the way
Do you edit CSS often? Of course you do. Let me help you make that [a better experience.](http://ricostacruz.com/vim-hyperstyle/)
<br>
## Thanks
**vim-closer** © 2015+, Rico Sta. Cruz. Released under the [MIT] License.<br>
Authored and maintained by Rico Sta. Cruz with help from contributors ([list][contributors]).
> [ricostacruz.com](http://ricostacruz.com) &nbsp;&middot;&nbsp;
> GitHub [@rstacruz](https://github.com/rstacruz) &nbsp;&middot;&nbsp;
> Twitter [@rstacruz](https://twitter.com/rstacruz)
[MIT]: http://mit-license.org/
[contributors]: http://github.com/rstacruz/vim-closer/contributors
161 changes: 161 additions & 0 deletions autoload/closer.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
if exists("g:closer_autoloaded") | finish | endif
let g:closer_autoloaded=1

if maparg("<Plug>CloserClose") == ""
inoremap <silent> <SID>CloserClose <C-R>=closer#close()<CR>
imap <script> <Plug>CloserClose <SID>CloserClose
endif

"
" Enables closer for the current buffer.
"

function! closer#enable()
if ! exists('b:closer_flags') | return | endif
let b:closer = 1
let map = maparg('<CR>', 'i', 0, 1)
let rhs = substitute(get(map, 'rhs', ''), '\c<sid>', '<SNR>' . get(map, 'sid') . '_', 'g')
if rhs =~# 'closer#closer' || get(map, 'buffer')
return
endif
if get(map, 'expr')
exe 'imap <script><silent><expr> <CR> closer#close(' . rhs . ')'
elseif rhs =~? '^<cr>' && rhs !~? '<plug>'
exe 'imap <silent><script> <CR>' rhs . '<SID>closer#close'
elseif rhs =~? '^<cr>'
exe 'imap <silent> <CR>' rhs . '<SID>closer#close'
elseif empty(rhs)
imap <script><silent><expr> <CR> closer#close("\r")
endif
endfunction

"
" Adds a closing bracket if needed.
" Executed after pressing <CR>
"

function! closer#close(...)
if a:0 && type(a:1) == type('')
return a:1 . (a:1 =~# "\r" && empty(&buftype) ? "\<C-R>=closer#close()\r" : "")
endif
if ! get(b:, 'closer') | return '' | endif

" supress if it broke off a line (pressed enter not at the end)
if match(getline('.'), '^\s*$') == -1 | return '' | endif

let ln = line('.') - 1
let line = getline(ln)
let indent = matchstr(line, '^\s*')

" If it's the end of a non-self-closing tag name:
if line[-1:] == '>' && line[-2:] != '/>' && match(line, '\v\</[a-zA-Z0-9\.]*\>\s*$') == -1
while ln >= line('.') - 100
let line = getline(ln)
let ln -= 1
if match(line, '<[a-zA-Z0-9]*') > -1
let closetag = matchlist(line, '\v\<([a-zA-Z0-9\.]*)')[1]
" if len(closetag) > 0
return "\<Esc>a" .indent . "</" . closetag . ">\<C-O>O\<Esc>a" . indent . "\<Tab>\<Esc>A"
" endif
endif
endwhile
endif

let closetag = s:get_closing(line)
if closetag == '' | return "" | endif

let closetag = closetag . s:use_semicolon(ln)
" <esc>a will go back to the 0.
" I dont know why <esc>A is needed at the end, but it seems to fix
" pressing escape after expansion.
return "\<Esc>a" .indent . closetag . "\<C-O>O\<Esc>a" . indent . "\<Tab>\<Esc>A"
endfunction

"
" Returns the context of the function
" simply returns whatever's on the previous level of indentation
"

function! s:get_context()
let ln = line('.') - 1
let indent = strlen(matchstr(getline(ln), '^\s*'))
while ln > 0
let ln = prevnonblank(ln-1)
let lntext = getline(ln)
let nindent = strlen(matchstr(lntext, '^\s*'))
if nindent < indent | return lntext | endif
endwhile
return 0
endfunction

"
" Checks if a semicolon is needed for a given line number
"

function! s:use_semicolon(ln)
" Only add semicolons if the `;` flag is on.
if ! exists('b:closer') | return '' | endif
if match(b:closer_flags, ';') == -1 | return '' | endif

" Only add semicolons if another line has a semicolon.
let used_semi = search(';$', 'wn') > 0
if used_semi == "0" | return '' | endif

" Don't add semicolons for lines matching `no_semi`.
" This allows `function(){ .. }` and `class X { .. }` to not get semicolons.
let line = getline(a:ln)
let topline = getline(a:ln - 1)
if b:closer_no_semi != '0' && match(line, b:closer_no_semi) > -1
return ''
elseif b:closer_no_semi != '0' && b:closer_semi_check_top != '0' && match(topline, b:closer_no_semi) > -1
return ''
endif

" Don't add semicolons for context lines matching `semi_ctx`.
" This allows supressing semi's for those inside object literals
let ctx = s:get_context()
if ctx != '0'
" if context is not a js function, don't semicolonize
if b:closer_semi_ctx != '0' && match(ctx, b:closer_semi_ctx) == -1 | return '' | endif
endif

return ';'
endfunction

"
" Returns the closing tag for a given line
"
" get_closing('describe(function() {')
" => '});'
"
" get_closing('function x() {')
" => '}'
"

function! s:get_closing(line)
let i = -1
let clo = ''
while 1
let i = match(a:line, '[{}()\[\]]', i+1)
if i == -1 | break | endif
let ch = a:line[i]
if ch == '{'
let clo = '}' . clo
elseif ch == '}'
if clo[0] != '}' | return '' | endif
let clo = clo[1:]
elseif ch == '('
let clo = ')' . clo
elseif ch == ')'
if clo[0] != ')' | return '' | endif
let clo = clo[1:]
elseif ch == '['
let clo = ']' . clo
elseif ch == ']'
if clo[0] != ']' | return '' | endif
let clo = clo[1:]
endif
endwhile
return clo
endfunction
53 changes: 53 additions & 0 deletions doc/closer.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
*closer.txt* automatically close brackets
*vim-closer*

==============================================================================
INTRODUCTION *closer*

|closer| automatically closes brackets for you.

http://github.com/rstacruz/vim-closer

==============================================================================
CONFIGURATION *closer-configuration*

*g:closer_no_mappings*
Set this to `1` to suppress vim-closer's keybindings (default `null`). Use
this when using with other plugins that might also rely on binding `<CR>`.

When set to `1`, this requires setting bindings like so:
>
imap <CR> <CR><Plug>CloserClose
<
==============================================================================
BUFFER CONFIGURATION *closer-buffer-configuration*

Using configuration:~
See the plugin/closer.vim source for information on how to set
configuration flags for filetypes.
http://github.com/rstacruz/vim-closer/blob/master/plugin/closer.vim

*b:closer*
Enables vim-closer behavior. Set this to `0` to temprarily disable.

*b:closer_flags*
A list of flags. Available flags:

`([{` close these braces
`;` use semicolons

*b:closer_no_semi*
When the line matches this regexp, don't add semicolons.

In JavaScript, this allows you to not add semicolons for `function(){...}`
or `class` `X` `{...}`.

*b:closer_semi_ctx*
Only consider semicolons when the context line matches this regexp.

The context is the previous line that is indented higher than the current
line. In JavaScript, this allows you to only add semicolons in the
function context.

==============================================================================
vim:tw=78:ts=8:ft=help:norl:
Loading

0 comments on commit e1a9bc9

Please sign in to comment.