diff --git a/.gitignore b/.gitignore index 843fbca..8c5052f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ out dist node_modules .vscode-test/ +.DS_Store *.vsix \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4995541..a1eea34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # Changelog +## Version 0.0.5-alpha +* Easier configuration +* Supports multiple term languages +* On/Off extension toggle + ## Version 0.0.1-alpha * First release \ No newline at end of file diff --git a/README.md b/README.md index 0118de8..98e6304 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,12 @@ ### How to use it - Install it through VS Code extensions tab - Manually configure it through the settings page or use the template below on your `settings.json` file - +- Example: ```json { - "termPreview.absolutePathToProjectRoot": "", - "termPreview.innerPathToTermsRoot": "", - "termPreview.filePrefix": "", - "termPreview.language": "", - "termPreview.fileSuffix": "" + "termPreview.enabled": true, + "termPreview.absolutePathToTermRoot": "/Users/richard/big-project/terms/", + "termPreview.file": "terms.{{LANGUAGE}}.utf-8.inc", + "termPreview.languages": ["pt-br", "en-us"], } ``` \ No newline at end of file diff --git a/package.json b/package.json index 7672d9b..f75cf8a 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,18 @@ "displayName": "Term Preview", "description": "Preview your project's international terms", "publisher": "richard-bidin", + "author": { + "name": "Richard Bidin" + }, "repository": { "type": "git", "url": "https://github.com/nidib/term-preview" }, - "version": "0.0.1-alpha", + "bugs": { + "url": "https://github.com/nidib/term-preview/issues", + "email": "nidibdev@outlook.com" + }, + "version": "0.0.5-alpha", "engines": { "vscode": "^1.63.0" }, @@ -18,45 +25,29 @@ "configuration": { "title": "Term Preview", "properties": { - "termPreview.absolutePathToProjectRoot": { - "type": "string", - "markdownDescription": "The absolute path to your project root", - "default": "" - }, - "termPreview.innerPathToTermsRoot": { - "type": "string", - "markdownDescription": "The path to the terms folder relative to the project root", - "default": "" + "termPreview.enabled": { + "order": 0, + "type": "boolean", + "markdownDescription": "Enables the term preview on hover", + "default": false }, - "termPreview.filePrefix": { + "termPreview.absolutePathToTermsRoot": { "type": "string", - "markdownDescription": "The file prefix", + "markdownDescription": "The absolute path to your terms root", "default": "" }, - "termPreview.language": { + "termPreview.file": { "type": "string", - "markdownDescription": "Goes in between prefix, and suffix", - "default": "en-us" - }, - "termPreview.fileSuffix": { - "type": "string", - "markdownDescription": "The file suffix including the extension", + "markdownDescription": "Your file name. `{{LANGUAGE}}` is the placeholder for the language", "default": "" }, - "termPreview.fileSeparator": { - "type": "string", - "markdownDescription": "Goes in between prefix, language, and suffix", - "default": "." - }, - "termPreview.showFlag": { - "type": "boolean", - "markdownDescription": "Whether or not to display the language flag", - "default": false - }, - "termPreview.watchForChanges": { - "type": "boolean", - "markdownDescription": "Whether or not to keep watching for changes on your file", - "default": false + "termPreview.languages": { + "type":"array", + "items": { + "type": "string" + }, + "markdownDescription": "The languages you want your terms translated to (must match file names)", + "default": ["en-us"] } } } diff --git a/src/@types/types.ts b/src/@types/types.ts index 27c5f25..1c82b2f 100644 --- a/src/@types/types.ts +++ b/src/@types/types.ts @@ -1,18 +1,15 @@ import * as vscode from 'vscode'; export interface ITermHover extends vscode.HoverProvider { - getTerms: MapCallback; - language: string; - showFlag: boolean; + getTranslationsByTerm: Callback; } export interface ExtensionConfig { - language: string; - path: string | null; - showFlag: boolean; - watchForChanges: boolean; + enabled: boolean, + filePath: string; + languages: string[]; } export type Map = { [key: string]: T }; -export type MapCallback = () => Map; \ No newline at end of file +export type Callback = (_arg0: I) => T; \ No newline at end of file diff --git a/src/app/app.ts b/src/app/app.ts index d019221..9b24050 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -2,55 +2,57 @@ import * as fs from 'fs'; import * as vscode from 'vscode'; import { ExtensionConfig, Map } from '../@types/types'; import { termsfileParserRegex } from '../utils/constants/regexConstants'; +import { getFilePaths } from '../utils/helpers/fileHelpers'; import getInitialConfig from '../utils/helpers/getConfig'; import TermHover from './termHover'; +const APP_STATUS_BAR_ID = 'app-name_status-bar'; + class App { config: ExtensionConfig; statusBarItem: vscode.StatusBarItem; - terms: Map; + terms: Map>; constructor() { this.config = getInitialConfig(); this.statusBarItem = this.getInitialStatusBarItem(); this.terms = {}; - this.getTerms = this.getTerms.bind(this); - this.handleFileChange = this.handleFileChange.bind(this); + this.getTranslationsByTerm = this.getTranslationsByTerm.bind(this); this.statusBarItem.show(); } - getTerms() { - return this.terms; + getInitialStatusBarItem() { + return vscode.window.createStatusBarItem(APP_STATUS_BAR_ID, vscode.StatusBarAlignment.Right); } - getInitialStatusBarItem() { - return vscode.window.createStatusBarItem('app-name_status-bar', vscode.StatusBarAlignment.Right); + getTranslationsByTerm(term: string): string[] { + const { languages } = this.config; + + return languages.map(language => this.terms[language][term]); } - getTermsFromFile(): Map { - const { path } = this.config; + getTermsFromFile(path: string): Map { + let terms: Map = {}; let file: string; let matchedFileTerms: IterableIterator; try { - file = fs.readFileSync(path as string, 'utf-8'); + file = fs.readFileSync(path, 'utf-8'); matchedFileTerms = file.matchAll(termsfileParserRegex); Array.from(matchedFileTerms).forEach(match => { const term = match[1]; const value = match[2]; - this.terms[term] = value; + terms[term] = value; }); - } catch (e) { - throw new Error('Could not find or parse the specified file'); - } finally { - this.setStatusBarText('Terms file loaded!', 'Your terms file seems to be loaded and parsed. You can now hover over a term!', 'check'); + } catch (_e) { + throw new Error(`Could not find or parse ${path}`); } - return this.terms; + return terms; } setStatusBarText(text: string, tooltip:string, icon: string ) { @@ -58,28 +60,29 @@ class App { this.statusBarItem.text = `$(${icon}) ${text}`; } - handleFileChange(): void { - this.terms = this.getTermsFromFile(); - } - run(context: vscode.ExtensionContext) { - const { path, showFlag, language } = this.config; + const { enabled, languages } = this.config; + let files: string[]; let termHover, disposableHover; - if (path) { - this.terms = this.getTermsFromFile(); - termHover = new TermHover(this.getTerms, showFlag, language); + if (!enabled) { + return; + } - if (this.config.watchForChanges) { - fs.watchFile(path, this.handleFileChange); - } + files = getFilePaths(); - disposableHover = vscode.languages.registerHoverProvider('*', termHover); + files.forEach((file, index) => { + const language = languages[index]; - context.subscriptions.push(disposableHover); - } else { - throw new Error('You must provide a the global and relative path to your terms file. Ctrl + , to set it up'); - } + this.terms[language] = this.getTermsFromFile(file); + }); + + this.setStatusBarText('Terms file(s) loaded!', 'Your file(s) seem(s) to be loaded and parsed', 'check'); + + termHover = new TermHover(this.getTranslationsByTerm); + disposableHover = vscode.languages.registerHoverProvider('*', termHover); + + context.subscriptions.push(disposableHover); } } diff --git a/src/app/termHover.ts b/src/app/termHover.ts index c58785c..8880f49 100644 --- a/src/app/termHover.ts +++ b/src/app/termHover.ts @@ -1,48 +1,40 @@ import * as vscode from 'vscode'; -import { ITermHover, MapCallback } from '../@types/types'; -import flags from '../utils/constants/flags'; +import { Callback, ITermHover } from '../@types/types'; import { termRegex } from '../utils/constants/regexConstants'; class TermHover implements ITermHover { - getTerms; - showFlag; - language; - - constructor(getTerms: MapCallback, showFlag: boolean, language: string) { - this.getTerms = getTerms; - this.showFlag = showFlag; - this.language = language; - } - - private getTranslation(translation: string): string { - if (this.showFlag) { - return `${flags[this.language]} ${translation}`; - } + getTranslationsByTerm; - return translation; + constructor(getTranslationsByTerm: Callback) { + this.getTranslationsByTerm = getTranslationsByTerm; } provideHover(document: vscode.TextDocument, position: vscode.Position, _token: vscode.CancellationToken): vscode.ProviderResult { const range = document.getWordRangeAtPosition(position); const word = document.getText(range); let isTerm = termRegex.test(word); - let translation, markdownTranslation; - let terms; - - if (isTerm) { - terms = this.getTerms(); - translation = terms[word]; - - if (translation) { - translation = this.getTranslation(translation); - markdownTranslation = new vscode.MarkdownString(translation); - markdownTranslation.supportHtml = true; - - return new vscode.Hover(markdownTranslation); - } + let translations: string[]; + let markdownTranslations: vscode.MarkdownString[] = []; + + if (!isTerm) { + return null; + } + + translations = this.getTranslationsByTerm(word); + + if (!translations.length) { + return null; } - return null; + markdownTranslations = translations.map(translation => { + const curr = new vscode.MarkdownString(translation); + + curr.supportHtml = true; + + return curr; + }); + + return new vscode.Hover(markdownTranslations); } } diff --git a/src/utils/constants/configDefaults.ts b/src/utils/constants/configDefaults.ts index 04355aa..81112f4 100644 --- a/src/utils/constants/configDefaults.ts +++ b/src/utils/constants/configDefaults.ts @@ -1,12 +1,8 @@ const configDefaults = { ABS_PATH: '', - REL_PATH: '', - FILE_PREFIX: '', - LANGUAGE: 'en-us', - FILE_SUFFIX: '', - FILE_SEPARATOR: '.', - SHOW_FLAG: false, - WATCH_FILES: true + ENABLED: false, + FILE: '', + LANGUAGES: ['en-us'] }; export default configDefaults; \ No newline at end of file diff --git a/src/utils/constants/fileNamePlaceholders.ts b/src/utils/constants/fileNamePlaceholders.ts new file mode 100644 index 0000000..fd21d58 --- /dev/null +++ b/src/utils/constants/fileNamePlaceholders.ts @@ -0,0 +1 @@ +export const LANGUAGE = '{{LANGUAGE}}'; \ No newline at end of file diff --git a/src/utils/constants/flags.ts b/src/utils/constants/flags.ts deleted file mode 100644 index db1a08c..0000000 --- a/src/utils/constants/flags.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Map } from '../../@types/types'; - -const flags: Map = { - 'pt-br': '🇧🇷' -}; - -export default flags; \ No newline at end of file diff --git a/src/utils/helpers/fileHelpers.ts b/src/utils/helpers/fileHelpers.ts new file mode 100644 index 0000000..05a5d15 --- /dev/null +++ b/src/utils/helpers/fileHelpers.ts @@ -0,0 +1,8 @@ +import { LANGUAGE } from '../constants/fileNamePlaceholders'; +import getInitialConfig from './getConfig'; + +export const getFilePaths = (): string[] => { + const { languages, filePath } = getInitialConfig(); + + return languages.map(language => filePath.replace(LANGUAGE, language)); +} \ No newline at end of file diff --git a/src/utils/helpers/getConfig.ts b/src/utils/helpers/getConfig.ts index 52520e9..d18c34c 100644 --- a/src/utils/helpers/getConfig.ts +++ b/src/utils/helpers/getConfig.ts @@ -4,19 +4,14 @@ import { ExtensionConfig } from '../../@types/types'; import configDefaults from '../../utils/constants/configDefaults'; function getInitialConfig(): ExtensionConfig { - const hoverTestConfiguration = vscode.workspace.getConfiguration('termPreview'); - const abs = hoverTestConfiguration.get('absolutePathToProjectRoot', configDefaults.ABS_PATH); - const rel = hoverTestConfiguration.get('innerPathToTermsRoot', configDefaults.REL_PATH); - const filePrefix = hoverTestConfiguration.get('filePrefix', configDefaults.FILE_PREFIX); - const language = hoverTestConfiguration.get('language', configDefaults.LANGUAGE); - const fileSuffix = hoverTestConfiguration.get('fileSuffix', configDefaults.FILE_SUFFIX); - const fileSeparator = hoverTestConfiguration.get('fileSeparator', configDefaults.FILE_SEPARATOR); - const showFlag = hoverTestConfiguration.get('showFlag', configDefaults.SHOW_FLAG); - const watchForChanges = hoverTestConfiguration.get('watchForChanges', configDefaults.WATCH_FILES); - const file = [filePrefix, language, fileSuffix].join(fileSeparator); - const path = (abs && rel && file) ? nodePath.join(abs, rel, file): null; + const appConfig = vscode.workspace.getConfiguration('termPreview'); + const abs = appConfig.get('absolutePathToTermsRoot', configDefaults.ABS_PATH); + const file = appConfig.get('file', configDefaults.FILE); + const languages = appConfig.get('languages', configDefaults.LANGUAGES); + const enabled = appConfig.get('enabled', configDefaults.ENABLED); + const filePath = nodePath.join(abs, file); - return { language, path, showFlag, watchForChanges }; + return { enabled, filePath, languages }; } export default getInitialConfig; \ No newline at end of file