DisposaBoy / GoSublime

A Golang plugin collection for SublimeText 3, providing code completion and other IDE-like features.
MIT License
3.42k stars 302 forks source link

potential issue with goimports #914

Open donotnoot opened 5 years ago

donotnoot commented 5 years ago

Hey all,

Not sure if this is an issue with GoSublime itself but thought I'd ask in case it is possible. My main editor has always been Sublime as it seems like it's the only editor worth using nowadays, apart from Vim. Since the features for Go were really lacking and Go is so picky with formatting, unused variables and whatnot I decided to give vscode a go. It works fine but it's ridiculously slow, I guess due to it being Electron based.

I've been trying GoSublime and it's pretty good, the only feature I'm missing really would be the automatic imports. I've enabled goimports in my margo.go file but it only works for stdlib imports, such as fmt or errors, etc. For example, I use spew (https://github.com/davecgh/go-spew) a lot to quickly debug stuff. Vscode would automatically import https://github.com/davecgh/go-spew, but it seems like GoSublime with goimports does not.

Is this behaviour expected? Configurable? It really is the only thing keeping me from switching back to Sublime, it's pretty annoying having to import the package every time I need to debug something quickly.

Thanks in advance.

DisposaBoy commented 5 years ago

How did you configure it?

GoSublime/margo doesn't do much except call the goimports binary. It should print any errors in the Sublime Text console.

donotnoot commented 5 years ago

I configured it to use goimports, but as you're saying that doesn't do what the vscode plugin does. This is more of a feature request I'm guessing so maybe it should not be an issue. I think that what the vscode plugin does is, after running go vet, if there are any undefined variables, it calls gopkgs like gopkgs -format "{{.Name}}:{{.ImportPath}}" -workDir . | grep {undefinedVariableName} to try to find the import that corresponds to the package that the undefined variable references to, and if it does find it, it adds it to the imports section of the file. Does that make any sense? The reason I'm asking is because I might try to go through the codebase and possibly submit a PR to add this feature, I just want to make sure that the package does not do this already. I really hate VSCode and anything Electron based, the bloat is very real.

DisposaBoy commented 5 years ago

I think I understand what you're saying, but it sounds like what goimports already does on its own minus the formatting. I assume you're already running goimports when you save the file so the only other time I can think you'd need the imports in the file is for auto-completion which should already work without needing to add them.

Alternatively, if you just want them to be added while typing, you can use AddUnimportedPackages but it doesn't have a very good UX.

donotnoot commented 5 years ago

Okay I see, so I think maybe I didn't configure GoSublime properly, given this go file

package main

import "fmt"

func main() {
    spew.Dump("test")
}

running goimports -d . returns this:

diff -u main.go.orig main.go
--- main.go.orig    2019-02-16 17:16:57.000000000 +0000
+++ main.go 2019-02-16 17:16:57.000000000 +0000
@@ -1,6 +1,6 @@
 package main

-import "fmt"
+import "github.com/davecgh/go-spew/spew"

 func main() {
    spew.Dump("test")

so that's exactly what I want, but if I save that file in sublime (latest dev build) with this config

package margo

import (
    "time"

    "margo.sh/golang"
    "margo.sh/mg"
)

// Margo is the entry-point to margo
func Margo(m mg.Args) {
    // See the documentation for `mg.Reducer`
    // comments beginning with `gs:` denote features that replace old GoSublime settings

    // add our reducers (margo plugins) to the store
    // they are run in the specified order
    // and should ideally not block for more than a couple milliseconds
    m.Use(
        // MOTD keeps you updated about new versions and important announcements
        //
        // It adds a new command `motd.sync` available via the UserCmd palette as `Sync MOTD`
        //
        // Interval can be set in order to enable automatic update fetching.
        //
        // When new updates are found, it displays the message in the status bar
        // e.g. `ā˜… margo.sh/cl/18.09.14 ā˜…` a url where you see the upcoming changes before updating
        //
        // It sends the following data to the url https://api.margo.sh/motd.json:
        // * current editor plugin name e.g. `?client=gosublime`
        //   this tells us which editor plugin's changelog to check
        // * current editor plugin version e.g. `?tag=r18.09.14-1`
        //   this allows us to determine if there any updates
        // * whether or not this is the first request of the day e.g. `?firstHit=1`
        //   this allows us to get an estimated count of active users without storing
        //   any personally identifiable data
        //
        // No other data is sent. For more info contact privacy at kuroku.io
        //
        &mg.MOTD{
            // Interval, if set, specifies how often to automatically fetch messages from Endpoint
            // Interval: 3600e9, // automatically fetch updates every hour
        },

        mg.NewReducer(func(mx *mg.Ctx) *mg.State {
            // By default, events (e.g. ViewSaved) are triggered in all files.
            // Replace `mg.AllLangs` with `mg.Go` to restrict events to Go(-lang) files.
            // Please note, however, that this mode is not tested
            // and saving a non-go file will not trigger linters, etc. for that go pkg
            return mx.SetConfig(mx.Config.EnabledForLangs(
                mg.AllLangs,
            ))
        }),

        // Add `go` command integration
        // this adds a new commands:
        // gs: these commands are all callable through 9o:
        // * go: Wrapper around the go command, adding linter support
        // * go.play: Automatically build and run go commands or run go test for packages
        //   with support for linting and unsaved files
        // * go.replay: Wrapper around go.play limited to a single instance
        //   by default this command is bound to ctrl+.,ctrl+r or cmd+.,cmd+r
        //
        // UserCmds are also added for `Go Play` and `Go RePlay`
        &golang.GoCmd{},

        // add the day and time to the status bar
        // &DayTimeStatus{},

        // both GoFmt and GoImports will automatically disable the GoSublime version
        // you will need to install the `goimports` tool manually
        // https://godoc.org/golang.org/x/tools/cmd/goimports
        //
        // gs: this replaces settings `fmt_enabled`, `fmt_tab_indent`, `fmt_tab_width`, `fmt_cmd`
        //
        // golang.GoFmt,
        // or
        golang.GoImports,

        // Configure general auto-completion behaviour
        &golang.MarGocodeCtl{
            // whether or not to include Test*, Benchmark* and Example* functions in the auto-completion list
            // gs: this replaces the `autocomplete_tests` setting
            ProposeTests: false,

            // Don't try to automatically import packages when auto-compeltion fails
            // e.g. when `json.` is typed, if auto-complete fails
            // "encoding/json" is imported and auto-complete attempted on that package instead
            // See AddUnimportedPackages
            NoUnimportedPackages: false,

            // If a package was imported internally for use in auto-completion,
            // insert it in the source code
            // See NoUnimportedPackages
            // e.g. after `json.` is typed, `import "encoding/json"` added to the code
            AddUnimportedPackages: false,

            // Don't preload packages to speed up auto-completion, etc.
            NoPreloading: false,

            // Don't suggest builtin types and functions
            // gs: this replaces the `autocomplete_builtins` setting
            NoBuiltins: false,
        },

        // Enable auto-completion
        // gs: this replaces the `gscomplete_enabled` setting
        &golang.Gocode{
            // show the function parameters. this can take up a lot of space
            ShowFuncParams: true,
        },

        // show func arguments/calltips in the status bar
        // gs: this replaces the `calltips` setting
        &golang.GocodeCalltips{},

        // use guru for goto-definition
        // new commands `goto.definition` and `guru.definition` are defined
        // gs: by default `goto.definition` is bound to ctrl+.,ctrl+g or cmd+.,cmd+g
        &golang.Guru{},

        // add some default context aware-ish snippets
        // gs: this replaces the `autocomplete_snippets` and `default_snippets` settings
        golang.Snippets,

        // add our own snippets
        // gs: this replaces the `snippets` setting
        MySnippets,

        // check the file for syntax errors
        // gs: this and other linters e.g. below,
        //     replaces the settings `gslint_enabled`, `lint_filter`, `comp_lint_enabled`,
        //     `comp_lint_commands`, `gslint_timeout`, `lint_enabled`, `linters`
        &golang.SyntaxCheck{},

        // Add user commands for running tests and benchmarks
        // gs: this adds support for the tests command palette `ctrl+.`,`ctrl+t` or `cmd+.`,`cmd+t`
        &golang.TestCmds{
            // additional args to add to the command when running tests and examples
            TestArgs: []string{},

            // additional args to add to the command when running benchmarks
            BenchArgs: []string{"-benchmem"},
        },

        // run `go install -i` on save
        // golang.GoInstall("-i"),
        // or
        // golang.GoInstallDiscardBinaries("-i"),
        //
        // GoInstallDiscardBinaries will additionally set $GOBIN
        // to a temp directory so binaries are not installed into your $GOPATH/bin
        //
        // the -i flag is used to install imported packages as well
        // it's only supported in go1.10 or newer

        // run `go vet` on save. go vet is ran automatically as part of `go test` in go1.10
        golang.GoVet(),

        // run `go test -race` on save
        // golang.GoTest("-race"),

        // run `golint` on save
        &golang.Linter{Name: "golint", Label: "Go/Lint"},

        // run gometalinter on save
        &golang.Linter{Name: "gometalinter", Args: []string{
            "--disable=gas",
            //"--fast",
        }},
    )
}

// DayTimeStatus adds the current day and time to the status bar
type DayTimeStatus struct {
    mg.ReducerType
}

func (dts DayTimeStatus) RMount(mx *mg.Ctx) {
    // kick off the ticker when we start
    dispatch := mx.Store.Dispatch
    go func() {
        ticker := time.NewTicker(1 * time.Second)
        for range ticker.C {
            dispatch(mg.Render)
        }
    }()
}

func (dts DayTimeStatus) Reduce(mx *mg.Ctx) *mg.State {
    // we always want to render the time
    // otherwise it will sometimes disappear from the status bar
    now := time.Now()
    format := "Mon, 15:04"
    if now.Second()%2 == 0 {
        format = "Mon, 15 04"
    }
    return mx.AddStatus(now.Format(format))
}

// MySnippets is a slice of functions returning our own snippets
var MySnippets = golang.SnippetFuncs(
    func(cx *golang.CompletionCtx) []mg.Completion {
        // if we're not in a block (i.e. function), do nothing
        if !cx.Scope.Is(golang.BlockScope) {
            return nil
        }

        return []mg.Completion{
            {
                Query: "if err",
                Title: "err != nil { return }",
                Src:   "if ${1:err} != nil {\n\treturn $0\n}",
            },
        }
    },
)

the file stays as it is, I get an underline GoVet error for the spew line and that's it

Am I missing something? Maybe I misconfigured GoSublime? go-vim seems to do fine when I do :GoImports

DisposaBoy commented 5 years ago

The config looks fine. Does it fmt at all? Maybe it can't find goimports (you have to install it manually). Check the Sublime Text console for errors.

Also make sure margo restarted after saving the margo.go file; a line like margo: agent#007: stopping should be printed in the Sublime Text console after saving it.

donotnoot commented 5 years ago

First of all, thanks for helping out.

So, if I make spew.Dump("hey") into spew.Dump("hey" ) it actually removes the spaces after the argument, but does not import the spew package, also the margo.go file is rebuilt when I save it, I can see the tasks running when I hit save on it.

Here's the output from the console just from opening the test file, adding a few spaces as shown above and hitting save.

startup, version: 3189 osx x64 channel: dev
executable: /Applications/Sublime Text.app/Contents/MacOS/Sublime Text
working dir: /
packages path: /Users/franco/Library/Application Support/Sublime Text 3/Packages
state path: /Users/franco/Library/Application Support/Sublime Text 3/Local
zip path: /Applications/Sublime Text.app/Contents/MacOS/Packages
zip path: /Users/franco/Library/Application Support/Sublime Text 3/Installed Packages
ignored_packages: ["Vintage"]
context must be an array
context must be an array
pre session restore time: 0.92936
using gpu buffer for window
startup time: 1.01418
environment variables loaded using: /bin/zsh -l
reloading plugin Default.arithmetic
reloading plugin Default.auto_indent_tag
reloading plugin Default.block
reloading plugin Default.colors
reloading plugin Default.comment
reloading plugin Default.convert_color_scheme
reloading plugin Default.convert_syntax
reloading plugin Default.copy_path
reloading plugin Default.detect_indentation
reloading plugin Default.echo
reloading plugin Default.exec
reloading plugin Default.fold
reloading plugin Default.font
reloading plugin Default.goto_line
reloading plugin Default.history_list
reloading plugin Default.indentation
reloading plugin Default.install_package_control
reloading plugin Default.kill_ring
reloading plugin Default.mark
reloading plugin Default.new_templates
reloading plugin Default.open_context_url
reloading plugin Default.open_in_browser
reloading plugin Default.pane
reloading plugin Default.paragraph
reloading plugin Default.paste_from_history
reloading plugin Default.profile
reloading plugin Default.quick_panel
reloading plugin Default.rename
reloading plugin Default.run_syntax_tests
reloading plugin Default.save_on_focus_lost
reloading plugin Default.scroll
reloading plugin Default.set_unsaved_view_name
reloading plugin Default.settings
reloading plugin Default.show_scope_name
reloading plugin Default.side_bar
reloading plugin Default.sort
reloading plugin Default.switch_file
reloading plugin Default.symbol
reloading plugin Default.transform
reloading plugin Default.transpose
reloading plugin Default.ui
reloading plugin CSS.css_completions
reloading plugin Diff.diff
reloading plugin HTML.encode_html_entities
reloading plugin HTML.html_completions
reloading plugin ShellScript.ShellScript
reloading plugin 0_package_control_loader.00-package_control
reloading plugin 0_package_control_loader.01-pygments
reloading plugin 0_package_control_loader.50-markupsafe
reloading plugin 0_package_control_loader.50-python-markdown
reloading plugin 0_package_control_loader.50-pyyaml
reloading plugin 0_package_control_loader.51-python-jinja2
reloading plugin 0_package_control_loader.55-jsonschema
reloading plugin 0_package_control_loader.55-mdpopups
reloading plugin All Autocomplete.all_views_completions
reloading plugin API Blueprint.APIBlueprint
reloading plugin API Blueprint.linter
apiblueprint: Defining 'cls.syntax' has been deprecated. Use http://www.sublimelinter.com/en/stable/linter_settings.html#selector
apiblueprint: Defining 'cls.selectors' has been deprecated. Use http://www.sublimelinter.com/en/stable/linter_settings.html#selector
reloading plugin Bootstrap 4 Autocomplete.bootstrap_4_autocomplete
reloading plugin Boxy Theme.BT
reloading plugin Boxy Theme.Icons
reloading plugin Case Conversion.case_conversion
reloading plugin Case Conversion.case_parse
reloading plugin DocBlockr.jsdocs
reloading plugin EditorConfig.EditorConfig
reloading plugin Emmet.emmet-plugin
reloading plugin Filter Lines.filter
reloading plugin Filter Lines.fold
reloading plugin Fix Mac Path.FixPath
reloading plugin GitSavvy.__init__
reloading plugin GitSavvy.git_savvy
reloading plugin Javascript Beautify.jsbeautify
reloading plugin Laravel 5 Artisan.Laravel 5 Artisan
reloading plugin Package Control.1_reloader
reloading plugin Package Control.2_bootstrap
reloading plugin Package Control.Package Control
reloading plugin PHP Companion.PHP Companion
reloading plugin PHP Completions Kit.plugin
reloading plugin Sass.sass_completions
reloading plugin Select Quoted.select_quotes
reloading plugin SublimeLinter-php.linter
reloading plugin SublimeLinter-phpcs.linter
reloading plugin SublimeLinter-phpmd.linter
reloading plugin SublimeLinter.__init__
reloading plugin SublimeLinter.active_linters_view
reloading plugin SublimeLinter.busy_indicator_view
reloading plugin SublimeLinter.goto_commands
reloading plugin SublimeLinter.highlight_view
reloading plugin SublimeLinter.log_handler
reloading plugin SublimeLinter.message_view
reloading plugin SublimeLinter.panel_view
reloading plugin SublimeLinter.status_bar_view
reloading plugin SublimeLinter.sublime_linter
reloading plugin Babel.Babel
reloading plugin GoSublime._after
reloading plugin GoSublime._before
reloading plugin GoSublime.GoSublime
reloading plugin GoSublime.gs9o
reloading plugin GoSublime.gscommands
reloading plugin GoSublime.gscomplete
reloading plugin GoSublime.gsdoc
reloading plugin GoSublime.gsev
reloading plugin GoSublime.gslint
reloading plugin GoSublime.gspalette
reloading plugin GoSublime.gstest
reloading plugin GoSublime.margo_sublime
reloading plugin Minify.Minify
reloading plugin Pretty JSON.PrettyJson
reloading plugin Pretty JSON.PrettyJsonListeners
plugins loaded
GoSublime r18.11.28-1: _before.init()
GoSublime r18.11.28-1: gs.init()
Emmet: No need to update PyV8
GoSublime r18.11.28-1: sh.init()
GoSublime r18.11.28-1 sh: using shell env GOPATH=/Users/franco/go
GoSublime r18.11.28-1 sh: using shell env GOROOT=/usr/local/go
GoSublime r18.11.28-1 sh: using shell env PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/opt/X11/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Users/franco/Library/Application Support/Sublime Text 3/Packages/GoSublime/bin:/Users/franco/Library/Application Support/Sublime Text 3/Packages/User/GoSublime/bin:/Users/franco/go/bin:/usr/local/opt/mysql@5.7/bin:/usr/local/sbin:/Users/franco/bin:/Users/franco/.composer/vendor/bin:/Users/franco/.fzf/bin:/usr/local/opt/go/bin
GoSublime r18.11.28-1 sh: go version: `go1.11.4` (raw version string `go1.11.4`)
GoSublime r18.11.28-1 sh: shell bootstrap took 0.402s
GoSublime r18.11.28-1: margo.init()
GoSublime r18.11.28-1: mg9.init()
[23:13:43] margo: agent#007: starting
GoSublime r18.11.28-1: _after.init()

** 2019-02-16 23:13:43.871936 **:
GoSublime init r18.11.28-1 (0.049s)
|   install margo: no
|   install state: done
| sublime.version: 3189
| sublime.channel: dev
|       about.ann: a18.11.28-1
|   about.version: r18.11.28-1
|         version: r18.11.28-1
|        platform: osx-x64
|            ~bin: ~/Library/Application Support/Sublime Text 3/Packages/User/GoSublime/osx-x64/bin
|       margo.exe: ~bin/gosublime.margo_r18.11.28-1_go1.11.4.exe (ok)
|          go.exe: /usr/local/go/bin/go (ok)
|      go.version: go1.11.4
|          GOROOT: /usr/local/go
|          GOPATH: ~/go
|           GOBIN: (not set)
|       set.shell: []
|       env.shell: /bin/zsh
|       shell.cmd: ['/bin/zsh', '-l', '-c', '${CMD}']
|    sh.bootstrap: 
|                >  using shell env GOPATH=~/go
|                >  using shell env GOROOT=/usr/local/go
|                >  using shell env PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/opt/X11/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:~/Library/Application Support/Sublime Text 3/Packages/GoSublime/bin:~/Library/Application Support/Sublime Text 3/Packages/User/GoSublime/bin:~/go/bin:/usr/local/opt/mysql@5.7/bin:/usr/local/sbin:~/bin:~/.composer/vendor/bin:~/.fzf/bin:/usr/local/opt/go/bin
|                >  go version: `go1.11.4` (raw version string `go1.11.4`)
|                >  shell bootstrap took 0.402s
|                >
--------------------------------

[23:13:44] margo: agent#007: ['/Users/franco/Library/Application Support/Sublime Text 3/Packages/GoSublime/bin/margo.sh', 'start', 'margo.sublime', '-codec', 'msgpack']
[23:13:44] margo: agent#007: log: Using margo extension: /Users/franco/Library/Application Support/Sublime Text 3/Packages/User/GoSublime/src/margo
[23:13:44] margo: agent#007: log: ``` go install -v -tags="margo margo_extension" margo.sh/cmd/margo.sublime ```
[23:13:44] margo: agent#007: log: ``` "/Users/franco/Library/Application Support/Sublime Text 3/Packages/GoSublime/bin/margo.sublime" -codec msgpack ```
[23:13:44] margo: agent#007: log: store.go:137: started
[23:13:45] margo: agent#007: log: ``` go install margo.sh/vendor/golang.org/x/tools/cmd/guru ```
[23:13:47] margo: agent#007: log: margocode.go:280: Scan GOPATH (/Users/franco/go/src)
[23:13:47] margo: agent#007: log: ``` packages=228, list=1.249s, decode=12ms, error=<nil> ```
[23:13:47] margo: agent#007: log: margocode.go:280: Scan GOROOT (/usr/local/go/src)
[23:13:47] margo: agent#007: log: ``` packages=286, list=1.268s, decode=8ms, error=<nil> ```
Package Control: Skipping automatic upgrade, last run at 2019-02-16 23:12:12, next run at 2019-02-17 00:12:12 or after

I usually run Sublime by doing subl . or subl proj\t from a terminal so the environment vars should be set properly. Also, which goimports finds it in my $GOPATH so I guess that's fine.

Any idea? Thanks šŸ‘

DisposaBoy commented 5 years ago

You always have to check for the existence of command by running them through 9o cmd+9.

I thought I could reproduce this with a file that's not in GOPATH, but I can't seem to reproduce it anymore.

Do you get auto-completion for spew.Dump? that would confirm that it's most likely an issue with goimports only.

You can debug goimports with the following reducer:

    mg.NewReducer(func(mx *mg.Ctx) *mg.State {
        return mx.AddBuiltinCmds(mg.BuiltinCmd{
            Name: "goimports-test",
            Run: func(cx *mg.CmdCtx) *mg.State {
                cx = cx.WithCmd("goimports", "-v", "-d", "-srcdir", cx.View.Filename())
                cx.Input = true
                return mg.Builtins.ExecCmd(cx)
            },
        })
    }),

It creates a new command goimports-test. With the test file open, press cmd+9 to open 9o and type goimports-test. It should output some debugging info from goimports as well as a diff if it would've changed the file.

donotnoot commented 5 years ago

Hey again, sorry I've been really busy with work and whatnot.

I think that I am missing some crucial piece of information regarding Go and their new Go Modules, I really don't understand how the whole modules thing works and I'm pretty sure this issue is related to me not setting up my workspace outside of GOPATH properly.

I will try to learn modules properly in the coming weeks as time allows and try to see if this keeps happening after I have learned my stuff regarding modules. In the mean time, please feel free to close this issue if you can't replicate it as I'm pretty sure it's just something not properly configured on my side...

Thanks for your time šŸ‘

edit:

I tried to add that reducer and after I did, the behaviour changed, now I get proper imports regardless of whether I'm in GOPATH or not, so that's pretty cool?

This is the output of the console

[ `goimports-test` | done ]
    2019/02/26 19:02:18.363362 fixImports(filename="/Users/me/repos/repo/main.go"), abs="/Users/me/repos/repo/main.go", srcDir="/Users/me/repos/repo/" ...

I'm not too sure why it seems to work now... but it does so I'll leave it like that. When I remove the reducer, it stops working again.