diff --git a/images/gutter-green.svg b/images/gutter-blockblue.svg
similarity index 55%
rename from images/gutter-green.svg
rename to images/gutter-blockblue.svg
index 84f3aa322..910bcbbea 100644
--- a/images/gutter-green.svg
+++ b/images/gutter-blockblue.svg
@@ -1,4 +1,4 @@
\ No newline at end of file
+
+
diff --git a/images/gutter-red.svg b/images/gutter-blockgreen.svg
similarity index 55%
rename from images/gutter-red.svg
rename to images/gutter-blockgreen.svg
index dbf4f8f26..155336039 100644
--- a/images/gutter-red.svg
+++ b/images/gutter-blockgreen.svg
@@ -1,4 +1,4 @@
\ No newline at end of file
+
+
diff --git a/images/gutter-blockred.svg b/images/gutter-blockred.svg
new file mode 100644
index 000000000..e5d75418f
--- /dev/null
+++ b/images/gutter-blockred.svg
@@ -0,0 +1,4 @@
+
diff --git a/images/gutter-blockyellow.svg b/images/gutter-blockyellow.svg
new file mode 100644
index 000000000..58079a3c8
--- /dev/null
+++ b/images/gutter-blockyellow.svg
@@ -0,0 +1,4 @@
+
diff --git a/images/gutter-slashblue.svg b/images/gutter-slashblue.svg
new file mode 100644
index 000000000..9a6150b15
--- /dev/null
+++ b/images/gutter-slashblue.svg
@@ -0,0 +1,3 @@
+
diff --git a/images/gutter-slashgreen.svg b/images/gutter-slashgreen.svg
new file mode 100644
index 000000000..7c6f5db62
--- /dev/null
+++ b/images/gutter-slashgreen.svg
@@ -0,0 +1,3 @@
+
diff --git a/images/gutter-slashred.svg b/images/gutter-slashred.svg
new file mode 100644
index 000000000..20f939e67
--- /dev/null
+++ b/images/gutter-slashred.svg
@@ -0,0 +1,3 @@
+
diff --git a/images/gutter-slashyellow.svg b/images/gutter-slashyellow.svg
new file mode 100644
index 000000000..36aa9735c
--- /dev/null
+++ b/images/gutter-slashyellow.svg
@@ -0,0 +1,3 @@
+
diff --git a/images/gutter-vertblue.svg b/images/gutter-vertblue.svg
new file mode 100644
index 000000000..b4504a4e6
--- /dev/null
+++ b/images/gutter-vertblue.svg
@@ -0,0 +1,3 @@
+
diff --git a/images/gutter-vertgreen.svg b/images/gutter-vertgreen.svg
new file mode 100644
index 000000000..5c677e2e8
--- /dev/null
+++ b/images/gutter-vertgreen.svg
@@ -0,0 +1,3 @@
+
diff --git a/images/gutter-vertred.svg b/images/gutter-vertred.svg
new file mode 100644
index 000000000..f3664f9f4
--- /dev/null
+++ b/images/gutter-vertred.svg
@@ -0,0 +1,3 @@
+
diff --git a/images/gutter-vertyellow.svg b/images/gutter-vertyellow.svg
new file mode 100644
index 000000000..ba5ed3a14
--- /dev/null
+++ b/images/gutter-vertyellow.svg
@@ -0,0 +1,3 @@
+
diff --git a/package.json b/package.json
index 7026a395a..12edc48e1 100644
--- a/package.json
+++ b/package.json
@@ -595,13 +595,73 @@
"scope": "resource"
},
"go.coverageDecorator": {
- "type": "string",
- "enum": [
- "highlight",
- "gutter"
- ],
- "default": "highlight",
- "description": "This option lets you choose the way to display code coverage. Highlight, as its name states, highlights the line in red or green, gutter shows the colors in the gutter of the editor.",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "default": "highlight",
+ "enum": [
+ "highlight",
+ "gutter"
+ ]
+ },
+ "coveredHighlightColor": {
+ "type": "string",
+ "default": "rgba(64,128,128,0.5)",
+ "description": "Color in the rgba format to use to highlight covered code."
+ },
+ "uncoveredHighlightColor": {
+ "type": "string",
+ "default": "rgba(128,64,64,0.25)",
+ "description": "Color in the rgba format to use to highlight uncovered code."
+ },
+ "coveredGutterStyle": {
+ "type": "string",
+ "default": "blockblue",
+ "enum": [
+ "blockblue",
+ "blockred",
+ "blockgreen",
+ "blockyellow",
+ "slashred",
+ "slashgreen",
+ "slashblue",
+ "slashyellow",
+ "verticalred",
+ "verticalgreen",
+ "verticalblue",
+ "verticalyellow"
+ ],
+ "description": "Gutter style to indicate covered code."
+ },
+ "uncoveredGutterStyle": {
+ "type": "string",
+ "default": "blockblue",
+ "enum": [
+ "blockblue",
+ "blockred",
+ "blockgreen",
+ "blockyellow",
+ "slashred",
+ "slashgreen",
+ "slashblue",
+ "slashyellow",
+ "verticalred",
+ "verticalgreen",
+ "verticalblue",
+ "verticalyellow"
+ ],
+ "description": "Gutter style to indicate covered code."
+ }
+ },
+ "default": {
+ "type": "highlight",
+ "coveredHighlightColor": "rgba(64,128,128,0.5)",
+ "uncoveredHighlightColor": "rgba(128,64,64,0.25)",
+ "coveredGutterStyle": "blockblue",
+ "uncoveredGutterStyle": "slashyellow"
+ },
+ "description": "This option lets you choose the way to display code coverage. Choose either to highlight the complete line or to show a decorator in the gutter. You can customize the color for the former and the style for the latter.",
"scope": "resource"
},
"go.testTimeout": {
diff --git a/src/goCover.ts b/src/goCover.ts
index 4d978b9e1..347646faf 100644
--- a/src/goCover.ts
+++ b/src/goCover.ts
@@ -11,19 +11,7 @@ import fs = require('fs');
import { showTestOutput, goTest } from './testUtils';
import rl = require('readline');
-export let coveredGutter;
-export let uncoveredGutter;
-
-let coveredHighLight = vscode.window.createTextEditorDecorationType({
- // Green
- backgroundColor: 'rgba(64,128,64,0.5)',
- isWholeLine: false
-});
-let uncoveredHighLight = vscode.window.createTextEditorDecorationType({
- // Red
- backgroundColor: 'rgba(128,64,64,0.5)',
- isWholeLine: false
-});
+let gutters;
let coverageFiles = {};
interface CoverageFile {
@@ -38,14 +26,29 @@ function clearCoverage() {
}
export function initGoCover(ctx: vscode.ExtensionContext) {
- coveredGutter = vscode.window.createTextEditorDecorationType({
- // Gutter green
- gutterIconPath: ctx.asAbsolutePath('images/gutter-green.svg')
- });
- uncoveredGutter = vscode.window.createTextEditorDecorationType({
- // Gutter red
- gutterIconPath: ctx.asAbsolutePath('images/gutter-red.svg')
- });
+ gutters = {
+ blockred: ctx.asAbsolutePath('images/gutter-blockred.svg'),
+ blockgreen: ctx.asAbsolutePath('images/gutter-blockgreen.svg'),
+ blockblue: ctx.asAbsolutePath('images/gutter-blockblue.svg'),
+ blockyellow: ctx.asAbsolutePath('images/gutter-blockyellow.svg'),
+ slashred: ctx.asAbsolutePath('images/gutter-slashred.svg'),
+ slashgreen: ctx.asAbsolutePath('images/gutter-slashgreen.svg'),
+ slashblue: ctx.asAbsolutePath('images/gutter-slashblue.svg'),
+ slashyellow: ctx.asAbsolutePath('images/gutter-slashyellow.svg'),
+ verticalred: ctx.asAbsolutePath('images/gutter-vertred.svg'),
+ verticalgreen: ctx.asAbsolutePath('images/gutter-vertgreen.svg'),
+ verticalblue: ctx.asAbsolutePath('images/gutter-vertblue.svg'),
+ verticalyellow: ctx.asAbsolutePath('images/gutter-vertyellow.svg')
+ };
+
+ const goConfig = vscode.workspace.getConfiguration('go');
+ const inspectResult = goConfig.inspect('coverageDecorator');
+ if (typeof inspectResult.globalValue === 'string') {
+ goConfig.update('coverageDecorator', { type: inspectResult.globalValue }, vscode.ConfigurationTarget.Global);
+ }
+ if (typeof inspectResult.workspaceValue === 'string') {
+ goConfig.update('coverageDecorator', { type: inspectResult.workspaceValue }, vscode.ConfigurationTarget.Workspace);
+ }
}
export function removeCodeCoverage(e: vscode.TextDocumentChangeEvent) {
@@ -137,26 +140,76 @@ function applyCoverage(remove: boolean = false) {
});
}
+// getCoverageDecorator fetches the value of the go.coverageDecorator
+// setting; historical values may be simply the string 'highlight' or
+// 'gutter' so we want to have sensible defaults for those (and if it's a
+// string but not one of those strings we just return the highlight default)
+//
+// However, modern versions should have an object with appropriate fields,
+// so if it's not a string we just make sure we have all the fields we need.
+function getCoverageDecorator(cfg: vscode.WorkspaceConfiguration) {
+ // These defaults are chosen to be distinguishable
+ // in nearly any color scheme (even Red) as well as by people
+ // who have difficulties with color perception. There are also
+ // enough options that everyone (we hope) should be able to
+ // find a choice that pleases them.
+ let defaults = {
+ type: 'highlight',
+ coveredHighlightColor: 'rgba(64,128,128,0.5)',
+ uncoveredHighlightColor: 'rgba(128,64,64,0.25)',
+ coveredGutterStyle: 'blockblue',
+ uncoveredGutterStyle: 'slashyellow'
+ };
+
+ let coverageDecorator = cfg['coverageDecorator'];
+ if (typeof (coverageDecorator) === 'string') {
+ defaults.type = coverageDecorator;
+ } else {
+ // look at all the values in coverageDecorator and overwrite the
+ // equivalent in defaults (this way coverageDecorator overrides
+ // every default but the result will still have all required fields).
+ for (let k in coverageDecorator) {
+ defaults[k] = coverageDecorator[k];
+ }
+ }
+
+ // before we're done, we need to turn these names into actual decorations
+ defaults['coveredGutter'] = vscode.window.createTextEditorDecorationType({
+ gutterIconPath: gutters[defaults.coveredGutterStyle]
+ });
+ defaults['uncoveredGutter'] = vscode.window.createTextEditorDecorationType({
+ gutterIconPath: gutters[defaults.uncoveredGutterStyle]
+ });
+ defaults['coveredHighLight'] = vscode.window.createTextEditorDecorationType({
+ backgroundColor: defaults.coveredHighlightColor
+ });
+ defaults['uncoveredHighLight'] = vscode.window.createTextEditorDecorationType({
+ backgroundColor: defaults.uncoveredHighlightColor
+ });
+
+ return defaults;
+}
+
function highlightCoverage(editor: vscode.TextEditor, file: CoverageFile, remove: boolean) {
let cfg = vscode.workspace.getConfiguration('go', editor.document.uri);
let coverageOptions = cfg['coverageOptions'];
- let coverageDecorator = cfg['coverageDecorator'];
+ let coverageDecorator = getCoverageDecorator(cfg);
- editor.setDecorations(coveredGutter, []);
- editor.setDecorations(coveredHighLight, []);
- editor.setDecorations(uncoveredGutter, []);
- editor.setDecorations(uncoveredHighLight, []);
+ editor.setDecorations(coverageDecorator['coveredGutter'], []);
+ editor.setDecorations(coverageDecorator['coveredHighLight'], []);
+ editor.setDecorations(coverageDecorator['uncoveredGutter'], []);
+ editor.setDecorations(coverageDecorator['uncoveredHighLight'], []);
if (remove) {
return;
}
if (coverageOptions === 'showCoveredCodeOnly' || coverageOptions === 'showBothCoveredAndUncoveredCode') {
- editor.setDecorations(coverageDecorator === 'gutter' ? coveredGutter : coveredHighLight, file.coveredRange);
+ editor.setDecorations(coverageDecorator.type === 'gutter' ? coverageDecorator['coveredGutter'] : coverageDecorator['coveredHighLight'], file.coveredRange);
}
if (coverageOptions === 'showUncoveredCodeOnly' || coverageOptions === 'showBothCoveredAndUncoveredCode') {
- editor.setDecorations(coverageDecorator === 'gutter' ? uncoveredGutter : uncoveredHighLight, file.uncoveredRange);
+ editor.setDecorations(coverageDecorator.type === 'gutter' ? coverageDecorator['uncoveredGutter'] : coverageDecorator['uncoveredHighLight'], file.uncoveredRange);
}
}
@@ -173,7 +226,7 @@ export function getCoverage(coverProfilePath: string, showErrOutput: boolean = f
lines.on('line', function (data: string) {
// go test coverageprofile generates output:
- // filename:StartLine.StartColumn,EndLine.EndColumn Hits IsCovered
+ // filename:StartLine.StartColumn,EndLine.EndColumn Hits CoverCount
// The first line will be "mode: set" which will be ignored
let fileRange = data.match(/([^:]+)\:([\d]+)\.([\d]+)\,([\d]+)\.([\d]+)\s([\d]+)\s([\d]+)/);
if (!fileRange) return;
@@ -189,8 +242,8 @@ export function getCoverage(coverProfilePath: string, showErrOutput: boolean = f
// End Column converted to zero based
parseInt(fileRange[5]) - 1
);
- // If is Covered
- if (parseInt(fileRange[7]) === 1) {
+ // If is Covered (CoverCount > 0)
+ if (parseInt(fileRange[7]) > 0) {
coverage.coveredRange.push({ range });
}
// Not Covered