-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
go.mod file support #1931
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
go.mod file support #1931
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
let s:go_major_version = "" | ||
|
||
function! go#mod#Format() abort | ||
" go mod only exists in `v1.11` | ||
if empty(s:go_major_version) | ||
let tokens = matchlist(go#util#System("go version"), '\d\+.\(\d\+\) ') | ||
let s:go_major_version = str2nr(tokens[1]) | ||
endif | ||
|
||
if s:go_major_version < "11" | ||
call go#util#EchoError("Go v1.11 is required to format go.mod file") | ||
return | ||
endif | ||
|
||
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?') | ||
|
||
" Save cursor position and many other things. | ||
let l:curw = winsaveview() | ||
|
||
" Write current unsaved buffer to a temp file | ||
let l:tmpname = tempname() . '.mod' | ||
call writefile(go#util#GetLines(), l:tmpname) | ||
if go#util#IsWin() | ||
let l:tmpname = tr(l:tmpname, '\', '/') | ||
endif | ||
|
||
let current_col = col('.') | ||
let l:args = ['go', 'mod', 'edit', '--fmt', l:tmpname] | ||
let [l:out, l:err] = go#util#Exec(l:args) | ||
let diff_offset = len(readfile(l:tmpname)) - line('$') | ||
|
||
if l:err == 0 | ||
call go#mod#update_file(l:tmpname, fname) | ||
else | ||
let errors = s:parse_errors(fname, l:out) | ||
call s:show_errors(errors) | ||
endif | ||
|
||
" We didn't use the temp file, so clean up | ||
call delete(l:tmpname) | ||
|
||
" Restore our cursor/windows positions. | ||
call winrestview(l:curw) | ||
|
||
" be smart and jump to the line the new statement was added/removed | ||
call cursor(line('.') + diff_offset, current_col) | ||
|
||
" Syntax highlighting breaks less often. | ||
syntax sync fromstart | ||
endfunction | ||
|
||
" update_file updates the target file with the given formatted source | ||
function! go#mod#update_file(source, target) | ||
" remove undo point caused via BufWritePre | ||
try | silent undojoin | catch | endtry | ||
|
||
let old_fileformat = &fileformat | ||
if exists("*getfperm") | ||
" save file permissions | ||
let original_fperm = getfperm(a:target) | ||
endif | ||
|
||
call rename(a:source, a:target) | ||
|
||
" restore file permissions | ||
if exists("*setfperm") && original_fperm != '' | ||
call setfperm(a:target , original_fperm) | ||
endif | ||
|
||
" reload buffer to reflect latest changes | ||
silent edit! | ||
|
||
let &fileformat = old_fileformat | ||
let &syntax = &syntax | ||
|
||
let l:listtype = go#list#Type("GoModFmt") | ||
|
||
" the title information was introduced with 7.4-2200 | ||
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640 | ||
if has('patch-7.4.2200') | ||
" clean up previous list | ||
if l:listtype == "quickfix" | ||
let l:list_title = getqflist({'title': 1}) | ||
else | ||
let l:list_title = getloclist(0, {'title': 1}) | ||
endif | ||
else | ||
" can't check the title, so assume that the list was for go fmt. | ||
let l:list_title = {'title': 'Format'} | ||
endif | ||
|
||
if has_key(l:list_title, "title") && l:list_title['title'] == "Format" | ||
call go#list#Clean(l:listtype) | ||
endif | ||
endfunction | ||
|
||
" parse_errors parses the given errors and returns a list of parsed errors | ||
function! s:parse_errors(filename, content) abort | ||
let splitted = split(a:content, '\n') | ||
|
||
" list of errors to be put into location list | ||
let errors = [] | ||
for line in splitted | ||
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\s*\(.*\)') | ||
if !empty(tokens) | ||
call add(errors,{ | ||
\"filename": a:filename, | ||
\"lnum": tokens[2], | ||
\"text": tokens[3], | ||
\ }) | ||
endif | ||
endfor | ||
|
||
return errors | ||
endfunction | ||
|
||
" show_errors opens a location list and shows the given errors. If the given | ||
" errors is empty, it closes the the location list | ||
function! s:show_errors(errors) abort | ||
let l:listtype = go#list#Type("GoModFmt") | ||
if !empty(a:errors) | ||
call go#list#Populate(l:listtype, a:errors, 'Format') | ||
call go#util#EchoError("GoModFmt returned error") | ||
endif | ||
|
||
" this closes the window if there are no errors or it opens | ||
" it if there is any | ||
call go#list#Window(l:listtype, len(a:errors)) | ||
endfunction | ||
|
||
function! go#mod#ToggleModFmtAutoSave() abort | ||
if go#config#ModFmtAutosave() | ||
call go#config#SetModFmtAutosave(0) | ||
call go#util#EchoProgress("auto mod fmt disabled") | ||
return | ||
end | ||
|
||
call go#config#SetModFmtAutosave(1) | ||
call go#util#EchoProgress("auto mod fmt enabled") | ||
endfunction |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
" gomod.vim: Vim filetype plugin for Go assembler. | ||
|
||
if exists("b:did_ftplugin") | ||
finish | ||
endif | ||
let b:did_ftplugin = 1 | ||
|
||
let b:undo_ftplugin = "setl fo< com< cms<" | ||
|
||
setlocal formatoptions-=t | ||
|
||
setlocal comments=s1:/*,mb:*,ex:*/,:// | ||
setlocal commentstring=//\ %s | ||
|
||
" vim: sw=2 ts=2 et |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
command! -nargs=0 -range GoModFmt call go#mod#Format() | ||
|
||
command! -nargs=0 GoModFmtAutoSaveToggle call go#mod#ToggleModFmtAutoSave() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
nnoremap <silent> <Plug>(go-mod-fmt) :<C-u>call go#mod#Format()<CR> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
" gomod.vim: Vim syntax file for go.mod file | ||
" | ||
" Quit when a (custom) syntax file was already loaded | ||
if exists("b:current_syntax") | ||
finish | ||
endif | ||
|
||
syntax case match | ||
|
||
" match keywords | ||
syntax keyword gomodModule module | ||
syntax keyword gomodRequire require | ||
syntax keyword gomodExclude exclude | ||
syntax keyword gomodReplace replace | ||
|
||
" require, exclude and replace can be also grouped into block | ||
syntax region gomodRequire start='require (' end=')' transparent contains=gomodRequire,gomodVersion | ||
syntax region gomodExclude start='exclude (' end=')' transparent contains=gomodExclude,gomodVersion | ||
syntax region gomodReplace start='replace (' end=')' transparent contains=gomodReplace,gomodVersion | ||
|
||
" set highlights | ||
highlight default link gomodModule Keyword | ||
highlight default link gomodRequire Keyword | ||
highlight default link gomodExclude Keyword | ||
highlight default link gomodReplace Keyword | ||
|
||
" comments are always in form of // ... | ||
syntax region gomodComment start="//" end="$" contains=@Spell | ||
highlight default link gomodComment Comment | ||
|
||
" make sure quoted import paths are higlighted | ||
syntax region gomodString start=+"+ skip=+\\\\\|\\"+ end=+"+ | ||
highlight default link gomodString String | ||
|
||
" replace operator is in the form of '=>' | ||
syntax match gomodReplaceOperator "\v\=\>" | ||
highlight default link gomodReplaceOperator Operator | ||
|
||
|
||
" highlight semver, note that this is very simple. But it works for now | ||
syntax match gomodVersion "v\d\+\.\d\+\.\d\+" | ||
syntax match gomodVersion "v\d\+\.\d\+\.\d\+-.*" | ||
highlight default link gomodVersion Identifier | ||
|
||
let b:current_syntax = "gomod" |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of passing in the parsed errors and calling
go#list#Populate
manually, can you use anerrorformat
string and callgo#list#ParseFormat
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tried it, but I think it'll not work because we run the command on a temporary file first (because
go mod edit
does an in-place edit). This means that the initial%f
is the temporary filename. This is copied fromfmt.vim
and it's the same issue. I'll check if I can do something ( I would preferParseFormat
indeed)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmmm... If you know the temporary filename, then it should be easy enough to do a
substitute(...)
ona:errors
before passing toParseFormat
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think at this point, this is too much a hack. We're having a working version and it really works fine. Not sure if it's worth doing it (same applies for gofmt).