From e6ebda86a11aaea06b3d04611426579ac0e87c41 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Tue, 24 Aug 2021 09:33:10 +0200 Subject: [PATCH] fix: fix wrapping issue in `trace` command with compound words. (#1574) * fix: fix wrapping issue in `trace` command with compound words. --- packages/cspell/package.json | 2 +- packages/cspell/src/traceEmitter.test.ts | 84 ++++++++++++++++++++++++ packages/cspell/src/traceEmitter.ts | 11 ++-- packages/cspell/src/util/glob.ts | 2 +- 4 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 packages/cspell/src/traceEmitter.test.ts diff --git a/packages/cspell/package.json b/packages/cspell/package.json index 65d585a94b8..26839360476 100644 --- a/packages/cspell/package.json +++ b/packages/cspell/package.json @@ -68,7 +68,6 @@ }, "homepage": "https://github.com/streetsidesoftware/cspell#readme", "dependencies": { - "@cspell/cspell-types": "^5.8.0", "chalk": "^4.1.2", "commander": "^8.1.0", "comment-json": "^4.1.1", @@ -84,6 +83,7 @@ "node": ">=12.0.0" }, "devDependencies": { + "@cspell/cspell-types": "^5.8.0", "@types/fs-extra": "^9.0.12", "@types/glob": "^7.1.4", "@types/micromatch": "^4.0.2", diff --git a/packages/cspell/src/traceEmitter.test.ts b/packages/cspell/src/traceEmitter.test.ts new file mode 100644 index 00000000000..6bc14da77f0 --- /dev/null +++ b/packages/cspell/src/traceEmitter.test.ts @@ -0,0 +1,84 @@ +import { emitTraceResults } from './traceEmitter'; +import strip from 'strip-ansi'; +import { TraceResult } from './application'; + +describe('traceEmitter', () => { + test('empty', () => { + const lines: string[] = []; + jest.spyOn(console, 'log').mockImplementation((a) => lines.push(strip(a))); + emitTraceResults([], { cwd: '/', lineWidth: 80 }); + expect(lines).toEqual(['Word F Dictionary Dictionary Location ']); + }); + + test('narrow screen with compound words', () => { + const lines: string[] = []; + jest.spyOn(console, 'log').mockImplementation((a) => lines.push(strip(a))); + const lineWidth = 80; + emitTraceResults(sampleResults(), { cwd: '/this_is_a_very/long/path', lineWidth }); + expect(lines.reduce((a, b) => Math.max(a, b.length), 0)).toBeLessThanOrEqual(lineWidth); + expect(lines).toEqual([ + 'Word F Dictionary Dictionary Location ', + 'errorcode ! forbid-words* forbid-words.txt', + 'errorcode I ignore-words* ignore-words.txt', + expect.stringContaining('error+code * my-special-words* '), + 'errorcode * project-words project-words.txt', + ]); + const out = lines.join('\n'); + expect(out).toEqual(expect.stringContaining('my-special-words.txt\n')); + }); +}); + +const _sampleResults: TraceResult[] = [ + { + word: 'errorcode', // cspell:ignore errorcode + found: true, + foundWord: 'error+code', + forbidden: false, + noSuggest: false, + dictName: 'my-special-words', + dictActive: true, + dictSource: '/this_is_a_very/long/path/which/should/not/fit/fully/into/the/space/my-special-words.txt', + configSource: 'the config source', + errors: undefined, + }, + { + word: 'errorcode', // cspell:ignore errorcode + found: true, + foundWord: 'errorcode', + forbidden: false, + noSuggest: false, + dictName: 'project-words', + dictActive: false, + dictSource: '/this_is_a_very/long/path/project-words.txt', + configSource: 'the config source', + errors: undefined, + }, + { + word: 'errorcode', // cspell:ignore errorcode + found: true, + foundWord: 'errorcode', + forbidden: true, + noSuggest: false, + dictName: 'forbid-words', + dictActive: true, + dictSource: '/this_is_a_very/long/path/forbid-words.txt', + configSource: 'the config source', + errors: undefined, + }, + { + word: 'errorcode', // cspell:ignore errorcode + found: true, + foundWord: 'errorcode', + forbidden: false, + noSuggest: true, + dictName: 'ignore-words', + dictActive: true, + dictSource: '/this_is_a_very/long/path/ignore-words.txt', + configSource: 'the config source', + errors: undefined, + }, +]; + +function sampleResults() { + return _sampleResults; +} diff --git a/packages/cspell/src/traceEmitter.ts b/packages/cspell/src/traceEmitter.ts index 3777b8ee796..de056ae4a5a 100644 --- a/packages/cspell/src/traceEmitter.ts +++ b/packages/cspell/src/traceEmitter.ts @@ -1,10 +1,12 @@ import { TraceResult } from './application'; import chalk = require('chalk'); +import strip from 'strip-ansi'; import * as Path from 'path'; export interface EmitTraceOptions { /** current working directory */ cwd: string; + lineWidth?: number; } const colWidthDictionaryName = 20; @@ -17,7 +19,7 @@ export function emitTraceResults(results: TraceResult[], options: EmitTraceOptio const cols: ColWidths = { word: maxWordLength, dictName: colWidthDictionaryName, - terminalWidth: process.stdout.columns || 120, + terminalWidth: options.lineWidth ?? (process.stdout.columns || 120), }; const col = new Intl.Collator(); @@ -40,7 +42,7 @@ function emitHeader(colWidths: ColWidths): void { pad('Dictionary', colWidths.dictName), pad('Dictionary Location', 30), ]; - console.log(chalk.underline(line.join(' '))); + console.log(chalk.underline(line.join(' ').slice(0, colWidths.terminalWidth))); } function emitTraceResult(r: TraceResult, colWidths: ColWidths, options: EmitTraceOptions): void { @@ -54,11 +56,12 @@ function emitTraceResult(r: TraceResult, colWidths: ColWidths, options: EmitTrac const dictName = pad(r.dictName.slice(0, widthName - 1) + a, widthName); const dictColor = r.dictActive ? chalk.yellowBright : chalk.rgb(200, 128, 50); const n = dictColor(dictName); - const used = [r.word.length, 1, widthName].reduce((a, b) => a + b, 3); + const info = [w, f, n].join(' ') + ' '; + const used = strip(info).length; const widthSrc = terminalWidth - used; const c = errors ? chalk.red : chalk.white; const s = c(formatDictionaryLocation(r.dictSource, widthSrc, options.cwd)); - const line = [w, f, n, s].join(' '); + const line = info + s; console.log(line); if (errors) { console.error('\t' + chalk.red(errors)); diff --git a/packages/cspell/src/util/glob.ts b/packages/cspell/src/util/glob.ts index 7fa3cdd764b..839ec17f966 100644 --- a/packages/cspell/src/util/glob.ts +++ b/packages/cspell/src/util/glob.ts @@ -2,7 +2,7 @@ import glob, { IGlob } from 'glob'; import * as path from 'path'; import { IOptions } from './IOptions'; import { GlobMatcher, GlobPatternWithRoot, fileOrGlobToGlob } from 'cspell-glob'; -import { CSpellUserSettings, Glob } from '@cspell/cspell-types'; +import type { CSpellUserSettings, Glob } from '@cspell/cspell-types'; export interface GlobOptions extends IOptions { cwd?: string;