Full Code of Olical/vim-enmasse for AI

master c2286f1d7bd7 cached
15 files
17.8 KB
5.2k tokens
1 requests
Download .txt
Repository: Olical/vim-enmasse
Branch: master
Commit: c2286f1d7bd7
Files: 15
Total size: 17.8 KB

Directory structure:
gitextract_gubi8ydj/

├── .gitignore
├── .travis.yml
├── README.md
├── UNLICENSE
├── autoload/
│   └── enmasse.vim
├── doc/
│   └── enmasse.txt
├── plugin/
│   └── enmasse.vim
└── test/
    ├── clearing.vader
    ├── enmasse.vader
    ├── grepable.txt
    ├── hints.vader
    ├── preview.vader
    ├── run
    ├── version.vader
    └── writing.vader

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
doc/tags
test/vader

================================================
FILE: .travis.yml
================================================
language: vim

before_script: |
  git clone https://github.com/junegunn/vader.vim.git

script: |
  vim -Nu <(cat << VIMRC
  filetype off
  set rtp+=vader.vim
  set rtp+=.
  set rtp+=after
  filetype plugin indent on
  VIMRC) -c 'Vader! test/*.vader' > /dev/null

================================================
FILE: README.md
================================================
# En Masse [![Build Status][travis-image]][travis]

[![Join the chat at https://gitter.im/Wolfy87/vim-enmasse](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Wolfy87/vim-enmasse?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Takes a quickfix list and makes it editable. You can then write each change back to their respective files using your favourite way of writing files, `:w` or `ZZ`, for example. Fix multiple [JSHint][] issues at once or perform a complex find and replace across your project all within the comfort of Vim.

![Animated demonstration](./images/example.gif)

## Using the plugin

As you can see in the demonstration above, all you have to do is populate a quickfix list in some way (I used [JSHint][], but you could use [Ag][], for example), then execute `:EnMasse`. This will open a new buffer with each line corresponding to a line in the quickfix list.

You can then edit each line in any way you want. When done just write this magical buffer and it will update each line in their corresponding files. For more information, check out [the documentation!][docs]

## Installation

### [vim-plug](https://github.com/junegunn/vim-plug#readme)

add this line to `.vimrc`

```
Plug 'Olical/vim-enmasse'
```

### [vim-pathogen](https://github.com/tpope/vim-pathogen#readme)

```
cd ~/.vim/bundle
git clone https://github.com/Olical/vim-enmasse
```

### [Vundle.vim](https://github.com/gmarik/Vundle.vim#readme)

add this line to `.vimrc`

```
Plugin 'Olical/vim-enmasse'
```

## Tests

Tests are performed using [vader][], to pull the dependencies and run them simply execute `./tests/run`. The tests are automatically executed by [TravisCI][travis] too, so keep an eye on that if you push changes or open a PR. The badge up the top of this README indicates the state of master, it should ALWAYS be green. A test should be written before any change is made.

## Author

[Oliver Caldwell][author-site] ([@OliverCaldwell][author-twitter])

## Unlicenced

Find the full [unlicense][] in the `UNLICENSE` file, but here's a snippet.

>This is free and unencumbered software released into the public domain.
>
>Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

Do what you want. Learn as much as you can. Unlicense more software.

[unlicense]: http://unlicense.org/
[author-site]: http://oli.me.uk/
[author-twitter]: https://twitter.com/OliverCaldwell
[jshint]: https://github.com/walm/jshint.vim
[ag]: https://github.com/rking/ag.vim
[docs]: https://github.com/Olical/vim-enmasse/blob/master/doc/enmasse.txt
[travis-image]: https://travis-ci.org/Olical/vim-enmasse.svg?branch=master
[travis]: https://travis-ci.org/Olical/vim-enmasse
[vader]: https://github.com/junegunn/vader.vim


================================================
FILE: UNLICENSE
================================================
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

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 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.

For more information, please refer to <http://unlicense.org>


================================================
FILE: autoload/enmasse.vim
================================================
function! enmasse#Open()
  let list = s:GetQuickfixList()
  let sourceLines = s:GetSourceLinesFromList(list)

  if len(list) > 0 && len(sourceLines) > 0
    call s:CreateEnMasseBuffer(list, sourceLines)
  else
    call s:EchoError("No entries to edit.")
  endif
endfunction

function! enmasse#GetVersion()
  return "1.1.1"
endfunction

function! enmasse#WriteCurrentBuffer()
  let list = b:enMasseList
  let sourceLines = getline(1, "$")

  if len(list) ==# len(sourceLines)
    call s:WriteSourceLinesAgainstList(list, sourceLines)
  else
    call s:EchoError("Mismatch between buffer lines and quickfix list. Refusing to write.")
  endif
endfunction

function! enmasse#DisplayQuickfixEntryForCurrentLine()
  let quickfixItem = s:GetQuickfixItemForCurrentLine()
  call s:EchoTruncated(quickfixItem.text)
endfunction

function! s:EchoTruncated(msg)
  let saved=&shortmess
  set shortmess+=T
  exec "echomsg a:msg"
  let &shortmess=saved
endfunction

function! s:EchoError(message)
  echohl ErrorMsg
  echo "EnMasse:" a:message
  echohl None
endfunction

function! s:GetQuickfixList()
  let list = getqflist()
  let uniqueList = []

  for item in list
    let existingItem = s:GetMatchingLineFromQuickfix(item, uniqueList)

    if has_key(existingItem, "bufnr")
      let existingItem.text = join([existingItem.text, item.text], " | ")
    else
      call add(uniqueList, item)
    endif
  endfor

  call sort(uniqueList, "s:SortByBufferAndLine")

  return uniqueList
endfunction

function! s:SortByBufferAndLine(i1, i2)
  if a:i1.bufnr > a:i2.bufnr || (a:i1.bufnr ==# a:i2.bufnr && a:i1.lnum > a:i2.lnum)
    return 1
  else
    return -1
  endif
endfunction

function! s:GetMatchingLineFromQuickfix(target, list)
  for item in a:list
    if a:target.bufnr ==# item.bufnr && a:target.lnum ==# item.lnum
      return item
    endif
  endfor

  return {}
endfunction

function! s:GetSourceLinesFromList(list)
  let sourceLines = []

  for item in a:list
    let file = bufname(item.bufnr)
    let line = item.lnum
    call add(sourceLines, s:GetLineFromFile(file, line))
  endfor

  return sourceLines
endfunction

function! s:GetLineFromFile(file, line)
  let lines = readfile(a:file, "b")
  return lines[a:line - 1]
endfunction

function! s:CreateEnMasseBuffer(list, sourceLines)
  noautocmd keepalt botright new! __EnMasse__
  setlocal stl=\ EnMasse
  setlocal buftype=acwrite
  setlocal bufhidden=hide
  setlocal noswapfile
  setlocal nobuflisted
  normal! gg"_dG
  call setbufvar(bufnr(''), "enMasseList", a:list)
  call append(0, a:sourceLines)
  normal! "_ddgg
  nnoremap <silent><buffer> <CR> :call <SID>OpenLineInPreviewWindow()<CR>
  set nomodified
  if line('$') < winheight(winnr())
      execute 'resize' line('$')
  end
endfunction

function! s:OpenLineInPreviewWindow()
  let quickfixItem = s:GetQuickfixItemForCurrentLine()
  let file = bufname(quickfixItem.bufnr)
  execute printf("pedit +%d %s", quickfixItem.lnum, file)
endfunction

function! s:GetQuickfixItemForCurrentLine()
  let list = b:enMasseList
  let currentLine = line(".")
  let quickfixItem = list[currentLine - 1]
  return quickfixItem
endfunction

function! s:WriteSourceLinesAgainstList(list, sourceLines)
  let toWrite = s:MergeChangesUnderPaths(a:list, a:sourceLines)

  for [filePath, fileChanges] in items(toWrite)
    let lines = readfile(filePath, "b")
    let changed = 0

    for lineChange in fileChanges
      if lines[lineChange.line] !=# lineChange.change
        let lines[lineChange.line] = lineChange.change
        let changed = 1
      endif
    endfor

    if changed
      execute "silent doautocmd FileWritePre " . filePath
      call writefile(lines, filePath, "b")
      execute "silent doautocmd FileWritePost " . filePath
    endif
  endfor

  set nomodified
  checktime
endfunction

function! s:MergeChangesUnderPaths(list, sourceLines)
  let index = 0
  let paths = {}

  for item in a:list
    let path = bufname(item.bufnr)
    let changes = get(paths, path, [])
    let paths[path] = add(changes, {"change": a:sourceLines[index], "line": item.lnum - 1})
    let index += 1
  endfor

  return paths
endfunction


================================================
FILE: doc/enmasse.txt
================================================
*enmasse.txt*

            =======================================================
                   ____  __ _    _  _   __   ____  ____  ____
                  (  __)(  ( \  ( \/ ) / _\ / ___)/ ___)(  __)
                   ) _) /    /  / \/ \/    \\___ \\___ \ ) _)
                  (____)\_)__)  \_)(_/\_/\_/(____/(____/(____)

              Edit every file in a quickfix list at the same time.
            =======================================================

===============================================================================
Introduction                                       *enmasse* *enmasse-introduction*

Takes a |quickfix| list and makes it editable. You can then write each change
back to their respective files using your favourite way of writing files, |:w|
or |ZZ|, for example. Fix multiple linting issues at once or perform a complex
find and replace across your project all within the comfort of Vim.

===============================================================================
Usage                                                             *enmasse-usage*

All you have to do is populate a quickfix list in some way (using JSHint or Ag,
for example), then execute :EnMasse. This will open a new buffer with each line
corresponding to a line in the quickfix list.

You can then edit each line in any way you want. When done just write this
magical buffer and it will update each line in their corresponding files. Do
not delete or create any new lines, that will not work, EnMasse will prevent
you from writing if it spots a discrepancy because it no longer knows which
lines should go where.

Pressing enter on a line will open the preview window to that line so you can
get the context of what you're about to edit. This mimics the functionality of
the quickfix list.

===============================================================================
Autocommands                                               *enmasse-autocommands*

When writing changes to files, EnMasse will batch writes together. That means
that if you have multiple changes for one file, only one write will take place.
With this in mind, EnMasse will fire |FileWritePre| and |FileWritePost| for
each file that is changed.

===============================================================================
Quickfix hints                                           *enmasse-quickfix-hints*

As you move your cursor through the lines the matching quickfix entry message
will be echoed at the bottom of the screen. So if you're scrolling through a
buffer created from a JSHint quickfix list, you'll be provided with the
corresponding JSHint message for each line at the bottom of the window.

If there were multiple quickfix entries for a single line (missing semi-colon
and unused variable, for example) then their messages will be merged into one
in the hint. If the message is too long to fit on one line it will be
truncated. It's either that or you have a "press enter to continue" prompt pop
up every time the echo wraps onto the next line. Not cool. So truncation is the
better alternative, even if you lose a bit of information sometimes.

===============================================================================
Author                                                           *enmasse-author*

Oliver Caldwell <http://oli.me.uk/> / @OliverCaldwell

===============================================================================
Unlicence                                                     *enmasse-unlicence*

This is free and unencumbered software released into the public domain. For
more information, please refer to <http://unlicense.org/> or the "README" of
this project.

vim:tw=78:sw=4:ts=4:ft=help:norl:


================================================
FILE: plugin/enmasse.vim
================================================
command! EnMasse :call enmasse#Open()
command! EnMasseVersion :echo enmasse#GetVersion()

augroup EnMasseDefault
  autocmd!
  autocmd WinLeave __EnMasse__ wincmd p
  autocmd BufWriteCmd __EnMasse__ call enmasse#WriteCurrentBuffer()
  autocmd CursorMoved __EnMasse__ call enmasse#DisplayQuickfixEntryForCurrentLine()
augroup END


================================================
FILE: test/clearing.vader
================================================
Execute (the line counts are correct):
  silent grep! -i a test/grepable.txt
  EnMasse
  let before = line("$")
  normal G
  quit
  silent grep! -i b test/grepable.txt
  EnMasse
  let after = line("$")

  AssertEqual 5, before
  AssertEqual 2, after


================================================
FILE: test/enmasse.vader
================================================
Before (read the example grepable file and grep for quickfix):
  let lines = readfile("test/grepable.txt", "b")
  silent grep! quickfix test/grepable.txt

Execute (can't call :EnMasse without a quickfix list):
  call setqflist([])

  redir => messages
  EnMasse
  redir END

  let result = get(split(messages, "\n"), -1, "")

  AssertEqual "EnMasse: No entries to edit.", result

Execute (:EnMasse with a quickfix list creates a buffer):
  EnMasse
  let name = bufname("%")
  quit

  AssertEqual "__EnMasse__", name

Execute (the buffer contains the correct line from the quickfix list):
  EnMasse
  let firstLine = getline("1")
  quit

  AssertEqual lines[1], firstLine

Execute (duplicate quickfix lines are joined together):
  silent grepadd! loaded test/grepable.txt
  EnMasse
  let firstLine = getline("1")
  let secondLine = getline("2")
  let lineCount = line("$")
  quit

  AssertEqual lines[1], firstLine
  AssertEqual lines[3], secondLine
  AssertEqual 2, lineCount


================================================
FILE: test/grepable.txt
================================================
This is an example file.
It should be loaded into the quickfix list.
Then you can run :EnMasse
And edit that quickfix list.
And this line is way too long so it will truncated. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin et ornare libero, quis vulputate odio. In luctus id velit sed gravida. Cras turpis nibh, luctus a lorem non, sollicitudin auctor justo. Vivamus tristique dolor a lectus gravida molestie. Nunc varius mi ante, vitae bibendum quam ultricies vitae.
Dupe!


================================================
FILE: test/hints.vader
================================================
Before (read the example grepable file and grep for quickfix):
  let lines = readfile("test/grepable.txt", "b")
  silent grep! quickfix test/grepable.txt

Execute (when the cursor is moved, the hint updates):
  EnMasse
  normal j

  redir => messages
  doautocmd CursorMoved
  redir END

  quit
  let result = get(split(messages, "\n"), -1, "")

  AssertEqual lines[3], result

Execute (when lines have been joined, the hint contains both of the results seperated with a pipe):
  silent grep! "Dupe!" test/grepable.txt
  silent grepadd! "Dupe!" test/grepable.txt
  EnMasse
  normal jk

  redir => messages
  doautocmd CursorMoved
  redir END

  quit
  let result = get(split(messages, "\n"), -1, "")

  AssertEqual join([lines[5], lines[5]], " | "), result

================================================
FILE: test/preview.vader
================================================
Before (set up an EnMasse buffer):
  let lines = readfile("test/grepable.txt", "b")
  silent grep! quickfix test/grepable.txt
  EnMasse

Execute (hitting enter on a line opens it in the preview window):
  let before = getline(".")
  execute "normal \<CR>\<C-W>k"
  let after = getline(".")
  let bufferName = expand("%")
  AssertEqual "test/grepable.txt", bufferName
  AssertEqual before, after
  pclose

================================================
FILE: test/run
================================================
#!/usr/bin/env bash

if [[ ! -d test/vader ]]; then
    git clone https://github.com/junegunn/vader.vim.git test/vader
else
    pushd test/vader
    git pull
    popd
fi

vim -Nu <(cat << VIMRC
filetype off
set rtp=.
set rtp+=test/vader
filetype plugin indent on
VIMRC
) -c 'Vader! test/*.vader' > /dev/null

================================================
FILE: test/version.vader
================================================
Before (set up regular expression):
  let versionRegExp = '\v\d+\.\d+\.\d+'

Execute (can print the version number with the command):
  redir => messages
  EnMasseVersion
  redir END

  let result = get(split(messages, "\n"), -1, "")

  Assert result =~# versionRegExp

Execute (can get the version number with the function):
  Assert enmasse#GetVersion() =~# versionRegExp

================================================
FILE: test/writing.vader
================================================
Before (define test data and setup EnMasse):
  let original = ["EnMasse is cOoL", "Hello, World!", "This is EnMasse.", "EnMasse is useful."]
  let expected = ["EnMasse is Cool", "Hello, World!", "This is EnMasse, a Vim plugin.", "EnMasse is handy."]
  let filePath = tempname()
  set nomodified
  call writefile(original, filePath)
  execute "silent grep! EnMasse " . filePath
  EnMasse

After (remove the temporary file and close the previous EnMasse buffer):
  call delete(filePath)
  quit!

Execute (editing and writing in an EnMasse buffer changes the file):
  %s/is EnMasse/is EnMasse, a Vim plugin/
  %s/useful/handy/
  %s/cOoL/Cool/
  set ignorecase
  write
  set noignorecase
  let actual = readfile(filePath)
  AssertEqual expected, actual

Execute (will not let you write if a line is deleted):
  normal dd
  redir => messages
  write
  redir END
  let actual = readfile(filePath)
  let latestMessage = get(split(messages, "\n"), -1, "")
  AssertEqual original, actual
  AssertEqual "EnMasse: Mismatch between buffer lines and quickfix list. Refusing to write.", latestMessage

Execute (will not let you write if a line is added):
  normal o
  redir => messages
  write
  redir END
  let actual = readfile(filePath)
  let latestMessage = get(split(messages, "\n"), -1, "")
  AssertEqual original, actual
  AssertEqual "EnMasse: Mismatch between buffer lines and quickfix list. Refusing to write.", latestMessage

Execute (doesn't write if no lines have changed):
  let before = getftime(filePath)
  write
  let after = getftime(filePath)
  AssertEqual before, after

Execute (changing a file that you have open will prompt for a reload):
  execute "split " . filePath
  %s/is EnMasse/is EnMasse, a Vim plugin/
  %s/useful/handy/
  write
  execute "normal! l\<CR>\<C-W>j"
  let bufferLines = getline(1, "$")
  let actual = readfile(filePath)
  AssertEqual actual, bufferLines

Execute (multiple changes to one file are written in one batched write):
  %s/is EnMasse/is EnMasse, a Vim plugin/
  %s/useful/handy/
  let writes = 0
  let actual = readfile(filePath)
  autocmd FileWritePost * let writes += 1
  write
  AssertEqual 1, writes
Download .txt
gitextract_gubi8ydj/

├── .gitignore
├── .travis.yml
├── README.md
├── UNLICENSE
├── autoload/
│   └── enmasse.vim
├── doc/
│   └── enmasse.txt
├── plugin/
│   └── enmasse.vim
└── test/
    ├── clearing.vader
    ├── enmasse.vader
    ├── grepable.txt
    ├── hints.vader
    ├── preview.vader
    ├── run
    ├── version.vader
    └── writing.vader
Condensed preview — 15 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (20K chars).
[
  {
    "path": ".gitignore",
    "chars": 19,
    "preview": "doc/tags\ntest/vader"
  },
  {
    "path": ".travis.yml",
    "chars": 261,
    "preview": "language: vim\n\nbefore_script: |\n  git clone https://github.com/junegunn/vader.vim.git\n\nscript: |\n  vim -Nu <(cat << VIMR"
  },
  {
    "path": "README.md",
    "chars": 2895,
    "preview": "# En Masse [![Build Status][travis-image]][travis]\n\n[![Join the chat at https://gitter.im/Wolfy87/vim-enmasse](https://b"
  },
  {
    "path": "UNLICENSE",
    "chars": 1210,
    "preview": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, c"
  },
  {
    "path": "autoload/enmasse.vim",
    "chars": 4121,
    "preview": "function! enmasse#Open()\n  let list = s:GetQuickfixList()\n  let sourceLines = s:GetSourceLinesFromList(list)\n\n  if len(l"
  },
  {
    "path": "doc/enmasse.txt",
    "chars": 3742,
    "preview": "*enmasse.txt*\n\n            =======================================================\n                   ____  __ _    _  _"
  },
  {
    "path": "plugin/enmasse.vim",
    "chars": 328,
    "preview": "command! EnMasse :call enmasse#Open()\ncommand! EnMasseVersion :echo enmasse#GetVersion()\n\naugroup EnMasseDefault\n  autoc"
  },
  {
    "path": "test/clearing.vader",
    "chars": 250,
    "preview": "Execute (the line counts are correct):\n  silent grep! -i a test/grepable.txt\n  EnMasse\n  let before = line(\"$\")\n  normal"
  },
  {
    "path": "test/enmasse.vader",
    "chars": 976,
    "preview": "Before (read the example grepable file and grep for quickfix):\n  let lines = readfile(\"test/grepable.txt\", \"b\")\n  silent"
  },
  {
    "path": "test/grepable.txt",
    "chars": 490,
    "preview": "This is an example file.\nIt should be loaded into the quickfix list.\nThen you can run :EnMasse\nAnd edit that quickfix li"
  },
  {
    "path": "test/hints.vader",
    "chars": 756,
    "preview": "Before (read the example grepable file and grep for quickfix):\n  let lines = readfile(\"test/grepable.txt\", \"b\")\n  silent"
  },
  {
    "path": "test/preview.vader",
    "chars": 403,
    "preview": "Before (set up an EnMasse buffer):\n  let lines = readfile(\"test/grepable.txt\", \"b\")\n  silent grep! quickfix test/grepabl"
  },
  {
    "path": "test/run",
    "chars": 307,
    "preview": "#!/usr/bin/env bash\n\nif [[ ! -d test/vader ]]; then\n    git clone https://github.com/junegunn/vader.vim.git test/vader\ne"
  },
  {
    "path": "test/version.vader",
    "chars": 373,
    "preview": "Before (set up regular expression):\n  let versionRegExp = '\\v\\d+\\.\\d+\\.\\d+'\n\nExecute (can print the version number with "
  },
  {
    "path": "test/writing.vader",
    "chars": 2145,
    "preview": "Before (define test data and setup EnMasse):\n  let original = [\"EnMasse is cOoL\", \"Hello, World!\", \"This is EnMasse.\", \""
  }
]

About this extraction

This page contains the full source code of the Olical/vim-enmasse GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 15 files (17.8 KB), approximately 5.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!