Skip to content

Commit a4429d7

Browse files
committed
Add support to lint changes in the live buffer in background
1 parent ca5bdfc commit a4429d7

File tree

1 file changed

+71
-3
lines changed

1 file changed

+71
-3
lines changed

linter.py

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,41 @@
11
import os
22
import json
33
import logging
4+
import tempfile
45
from SublimeLinter.lint import NodeLinter
56
from SublimeLinter.lint.linter import LintMatch
7+
from SublimeLinter.lint.persist import settings
68

79
logger = logging.getLogger('SublimeLinter.plugin.golangcilint')
810

11+
# Due to performance issues in golangci-lint, the linter will not attempt to
12+
# lint a maximum of one-hundred (100) files considering a delay of 100ms and
13+
# lint_mode equal to “background”. If the user increases the delay, the tool
14+
# will have more time to scan more files and analyze them.
15+
MAX_FILES = 100
916

1017
class Golangcilint(NodeLinter):
1118
cmd = "golangci-lint run --fast --out-format json"
1219
defaults = {"selector": "source.go"}
13-
axis_base = (1, 1)
20+
line_col_base = (1, 1)
21+
22+
def run(self, cmd, code):
23+
if not os.path.dirname(self.filename):
24+
logger.warning("cannot lint unsaved Go (golang) files")
25+
self.notify_failure()
26+
return ""
27+
28+
# If the user has configured SublimeLinter to run in background mode,
29+
# the linter will be unable to show warnings or errors in the current
30+
# buffer until the user saves the changes. To solve this problem, the
31+
# plugin will create a temporary directory, then will create symbolic
32+
# links of all the files in the current folder, then will write the
33+
# buffer into a file, and finally will execute the linter inside this
34+
# directory.
35+
if settings.get("lint_mode") == "background":
36+
return self._background_lint(cmd, code)
37+
else:
38+
return self._foreground_lint(cmd)
1439

1540
"""match regex against the command output"""
1641
def find_errors(self, output):
@@ -64,6 +89,49 @@ def find_errors(self, output):
6489

6590
yield self._lintissue(issue)
6691

92+
def finalize_cmd(self, cmd, context, at_value='', auto_append=False):
93+
"""prevents SublimeLinter from appending an unnecessary file"""
94+
return cmd
95+
96+
def _foreground_lint(self, cmd):
97+
return self.communicate(cmd)
98+
99+
def _background_lint(self, cmd, code):
100+
folder = os.path.dirname(self.filename)
101+
things = [f for f in os.listdir(folder) if f.endswith(".go")]
102+
nfiles = len(things)
103+
104+
if nfiles > MAX_FILES:
105+
logger.warning("too many Go (golang) files ({})".format(nfiles))
106+
self.notify_failure()
107+
return ""
108+
109+
try:
110+
"""create temporary folder to store the code from the buffer"""
111+
with tempfile.TemporaryDirectory(dir=folder, prefix=".golangcilint-") as tmpdir:
112+
for filepath in things:
113+
target = os.path.join(tmpdir, filepath)
114+
filepath = os.path.join(folder, filepath)
115+
"""create symbolic links to non-modified files"""
116+
if os.path.basename(target) != os.path.basename(self.filename):
117+
os.link(filepath, target)
118+
continue
119+
"""write the buffer into a file on disk"""
120+
with open(target, 'wb') as w:
121+
if isinstance(code, str):
122+
code = code.encode('utf8')
123+
w.write(code)
124+
"""point command to the temporary folder"""
125+
return self.communicate(cmd + [tmpdir])
126+
except FileNotFoundError:
127+
logger.warning("cannot lint non-existent folder “{}”".format(folder))
128+
self.notify_failure()
129+
return ""
130+
except PermissionError:
131+
logger.warning("cannot lint private folder “{}”".format(folder))
132+
self.notify_failure()
133+
return ""
134+
67135
def _shortname(self, issue):
68136
"""find and return short filename"""
69137
return os.path.basename(issue["Pos"]["Filename"])
@@ -114,7 +182,7 @@ def _lintissue(self, issue):
114182
match=issue,
115183
message=issue["Text"],
116184
error_type=self._severity(issue),
117-
line=issue["Pos"]["Line"] - self.axis_base[0],
118-
col=issue["Pos"]["Column"] - self.axis_base[1],
185+
line=issue["Pos"]["Line"] - self.line_col_base[0],
186+
col=issue["Pos"]["Column"] - self.line_col_base[1],
119187
code=issue["FromLinter"]
120188
)

0 commit comments

Comments
 (0)