From 1bbc62cf5e11f8e7d812c90d67c15aba85d355ae Mon Sep 17 00:00:00 2001 From: yangfan <18767120422@163.com> Date: Wed, 24 Jun 2020 15:29:04 +0800 Subject: [PATCH 1/8] feat: add style completion (#128) * feat: init * feat: update * feat: update readme * feat: uodate md --- extensions/iceworks-style-helper/CHANGELOG.md | 5 + extensions/iceworks-style-helper/README.en.md | 10 ++ extensions/iceworks-style-helper/README.md | 10 ++ extensions/iceworks-style-helper/package.json | 10 +- .../src/cssClassAutoCompete/index.ts | 88 ++++++++++++++++++ extensions/iceworks-style-helper/src/index.ts | 5 + .../src/inlineStyleAutoComplete/index.ts | 1 - .../src/styleInfoViewer/findStyle.ts | 48 ++++++++++ .../styleInfoViewer/findStyleDependencies.ts | 40 ++++++++ .../src/styleInfoViewer/findStyleSelectors.ts | 23 +++++ .../src/styleInfoViewer/index.ts | 93 +++++++++++++++++++ 11 files changed, 330 insertions(+), 3 deletions(-) create mode 100644 extensions/iceworks-style-helper/src/cssClassAutoCompete/index.ts create mode 100644 extensions/iceworks-style-helper/src/styleInfoViewer/findStyle.ts create mode 100644 extensions/iceworks-style-helper/src/styleInfoViewer/findStyleDependencies.ts create mode 100644 extensions/iceworks-style-helper/src/styleInfoViewer/findStyleSelectors.ts create mode 100644 extensions/iceworks-style-helper/src/styleInfoViewer/index.ts diff --git a/extensions/iceworks-style-helper/CHANGELOG.md b/extensions/iceworks-style-helper/CHANGELOG.md index e02b5833e..a4b676007 100644 --- a/extensions/iceworks-style-helper/CHANGELOG.md +++ b/extensions/iceworks-style-helper/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## 0.2.0 + +Add `class` name completions. + + ## 0.1.0 Initial release diff --git a/extensions/iceworks-style-helper/README.en.md b/extensions/iceworks-style-helper/README.en.md index 8badc05f9..662bacab6 100644 --- a/extensions/iceworks-style-helper/README.en.md +++ b/extensions/iceworks-style-helper/README.en.md @@ -10,6 +10,16 @@ When editing the 'style' attribute of a component in a JSX file, an automatic co ![demo](https://img.alicdn.com/tfs/TB1oyRBF1H2gK0jSZFEXXcqMpXa-1000-586.gif) +When editing the 'class' name of a CSS, LESS or SASS file, an automatic completion reminder will be given: + +![demo](https://img.alicdn.com/tfs/TB1l_zMFhD1gK0jSZFKXXcJrVXa-500-355.gif) + +Automatic completion When editing the 'style' name of a component in a JSX file, Use `cmd + click` (Windows: `ctrl + click`) jump to the identifier under the cursor. + +![demo](https://img.alicdn.com/tfs/TB1pb1ltYY1gK0jSZTEXXXDQVXa-1468-906.gif) + +![demo](https://img.alicdn.com/tfs/TB1UDGht.Y1gK0jSZFMXXaWcVXa-1468-906.gif) + ## More See the [Iceworks Pack](https://marketplace.visualstudio.com/items?itemName=iceworks-team.iceworks) to know more features. diff --git a/extensions/iceworks-style-helper/README.md b/extensions/iceworks-style-helper/README.md index b774e941e..66c9f9357 100644 --- a/extensions/iceworks-style-helper/README.md +++ b/extensions/iceworks-style-helper/README.md @@ -10,6 +10,16 @@ ![使用示例](https://img.alicdn.com/tfs/TB1oyRBF1H2gK0jSZFEXXcqMpXa-1000-586.gif) +在 CSS、LESS、SASS 文件中编辑 `class` 名称时给予自动补全提醒: + +![使用示例](https://img.alicdn.com/tfs/TB1l_zMFhD1gK0jSZFKXXcJrVXa-500-355.gif) + +在 JSX 文件中编辑组件的样式名时给予补全提醒并可通过 `cmd + 点击`( Windows: `ctrl + 点击` )跳转: + +![使用示例](https://img.alicdn.com/tfs/TB1pb1ltYY1gK0jSZTEXXXDQVXa-1468-906.gif) + +![使用示例](https://img.alicdn.com/tfs/TB1UDGht.Y1gK0jSZFMXXaWcVXa-1468-906.gif) + ## 更多 访问 [Iceworks Pack](https://marketplace.visualstudio.com/items?itemName=iceworks-team.iceworks) 了解更多 Iceworks 相关功能。 diff --git a/extensions/iceworks-style-helper/package.json b/extensions/iceworks-style-helper/package.json index 8bda860be..2b7f075fd 100644 --- a/extensions/iceworks-style-helper/package.json +++ b/extensions/iceworks-style-helper/package.json @@ -3,7 +3,7 @@ "displayName": "Iceworks Style Helper", "description": "Easily write styles in JSX.", "publisher": "iceworks-team", - "version": "0.1.1", + "version": "0.2.0", "engines": { "vscode": "^1.41.0" }, @@ -22,7 +22,10 @@ "onLanguage:javascript", "onLanguage:javascriptreact", "onLanguage:typescript", - "onLanguage:typescriptreact" + "onLanguage:typescriptreact", + "onLanguage:css", + "onLanguage:less", + "onLanguage:sass" ], "repository": { "type": "git", @@ -40,6 +43,9 @@ "typescript": "^3.6.4" }, "dependencies": { + "@babel/parser": "^7.10.3", + "@babel/traverse": "^7.10.3", + "css": "^2.2.4", "vscode-web-custom-data": "^0.1.4" } } diff --git a/extensions/iceworks-style-helper/src/cssClassAutoCompete/index.ts b/extensions/iceworks-style-helper/src/cssClassAutoCompete/index.ts new file mode 100644 index 000000000..4204b3e7c --- /dev/null +++ b/extensions/iceworks-style-helper/src/cssClassAutoCompete/index.ts @@ -0,0 +1,88 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as vscode from 'vscode'; +import { getFocusCodeInfo } from '../getFocusCodeInfo'; + +function unique(arr: string[]) { + return Array.from(new Set(arr)); +} + +function provideCompletionItems(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem[] { + const completions: vscode.CompletionItem[] = []; + const { word, directory } = getFocusCodeInfo(document, position); + + // Completion items for className writing. + if (word !== '.') { + return completions; + } + + let classNames: string[] = []; + // Read classNames from the file which is in the same directory. + fs.readdirSync(directory).forEach((file) => { + if (path.extname(file) === '.jsx' || path.extname(file) === '.tsx') { + const filePath = `${directory}/${file}`; + // Add className="xxx" and style={styles.xxx} + classNames = classNames.concat(getClassNames(filePath), getCSSModuleKeys(filePath)); + } + }); + + return unique(classNames).map( + className => + new vscode.CompletionItem( + `.${className}`, + vscode.CompletionItemKind.Text + ) + ); +} + +// Process className="xxx" +function getClassNames(filePath: string): string[] { + const code = fs.readFileSync(filePath, 'utf8'); + const reg = new RegExp('className="([\\w- ]+)"', 'g'); + + let classNames: string[] = []; + let matched: RegExpExecArray | null;; + + // eslint-disable-next-line + while ((matched = reg.exec(code)) !== null) { + const className = matched[1]; + // Process className="test1 test2" + if (className.includes(' ')) { + classNames = classNames.concat(className.split(' ')); + } else { + classNames.push(className); + } + } + return classNames; +} + +// Process style={styles.xxx} +function getCSSModuleKeys(filePath: string): string[] { + const code = fs.readFileSync(filePath, 'utf8'); + const reg = new RegExp('style=\\{styles\\.([\\w\\.]+)\\}', 'g'); + + const CSSModuleKeys: string[] = []; + let matched: RegExpExecArray | null; + + // eslint-disable-next-line + while ((matched = reg.exec(code)) !== null) { + CSSModuleKeys.push(matched[1]); + } + return CSSModuleKeys; +} + +// Set completion +export default function cssClassAutoCompete(context: vscode.ExtensionContext): void { + // Register completionItem provider + context.subscriptions.push( + vscode.languages.registerCompletionItemProvider( + [ + { scheme: 'file', language: 'css' }, + { scheme: 'file', language: 'less' }, + { scheme: 'file', language: 'sass' } + ], + { provideCompletionItems }, + '.' + ) + ); +}; \ No newline at end of file diff --git a/extensions/iceworks-style-helper/src/index.ts b/extensions/iceworks-style-helper/src/index.ts index b79200f14..4923d78ab 100644 --- a/extensions/iceworks-style-helper/src/index.ts +++ b/extensions/iceworks-style-helper/src/index.ts @@ -1,8 +1,13 @@ import * as vscode from 'vscode'; +import cssClassAutoCompete from './cssClassAutoCompete'; import inlineStyleAutoComplete from './inlineStyleAutoComplete'; +import styleInfoViewer from './styleInfoViewer'; + function activate(context: vscode.ExtensionContext) { + cssClassAutoCompete(context); inlineStyleAutoComplete(context); + styleInfoViewer(context); }; exports.activate = activate; \ No newline at end of file diff --git a/extensions/iceworks-style-helper/src/inlineStyleAutoComplete/index.ts b/extensions/iceworks-style-helper/src/inlineStyleAutoComplete/index.ts index f76963482..0b3c35168 100644 --- a/extensions/iceworks-style-helper/src/inlineStyleAutoComplete/index.ts +++ b/extensions/iceworks-style-helper/src/inlineStyleAutoComplete/index.ts @@ -102,7 +102,6 @@ function provideCompletionItems(document: vscode.TextDocument, position: vscode. }) } } - console.log(completions); return completions; } diff --git a/extensions/iceworks-style-helper/src/styleInfoViewer/findStyle.ts b/extensions/iceworks-style-helper/src/styleInfoViewer/findStyle.ts new file mode 100644 index 000000000..d8fafb509 --- /dev/null +++ b/extensions/iceworks-style-helper/src/styleInfoViewer/findStyle.ts @@ -0,0 +1,48 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import css from 'css'; +import { IStyleDependency } from './findStyleDependencies'; + +// https://www.npmjs.com/package/css +export interface IStylePosition { + start: { + line: number; + column: number; + }; + end: { + line: number; + column: number; + }; +} + +export interface IStyle { + type: string; + selectors: string[]; + position: IStylePosition; + file: string; + code: string; +} + +// Find style property by className, in some CSS files. +export function findStyle(directory: string, className: string, styleDependencies: IStyleDependency[] = []): IStyle | undefined { + let matched: IStyle | undefined; + + for (let i = 0, l = styleDependencies.length; i < l; i++) { + const file = path.join(directory, styleDependencies[i].source); + const stylesheet = css.parse(fs.readFileSync(file, 'utf-8')).stylesheet; + + matched = stylesheet.rules.find(rule => rule.selectors.includes(`.${className}`)); + + // Just find one matched stylesheet. + if (matched) { + matched.file = file; + matched.code = css.stringify({ + type: 'stylesheet', + stylesheet: { rules: [matched] } + }); + break; + } + } + + return matched; +}; diff --git a/extensions/iceworks-style-helper/src/styleInfoViewer/findStyleDependencies.ts b/extensions/iceworks-style-helper/src/styleInfoViewer/findStyleDependencies.ts new file mode 100644 index 000000000..c31ab1abb --- /dev/null +++ b/extensions/iceworks-style-helper/src/styleInfoViewer/findStyleDependencies.ts @@ -0,0 +1,40 @@ +import * as fs from 'fs'; +import * as babelParser from '@babel/parser'; +import traverse from '@babel/traverse'; + +// import styles from './xxx.css'; -> { source: './xxx.css', identifier: 'styles' } +// import './xxx.css'; -> { source: './xxx.css', identifier: null } +export interface IStyleDependency { + source: string; + identifier: string | null; +} + +// Find style dependencies, like import style form './index.css'; +export function findStyleDependencies(file: string) { + const StyleDependencies: IStyleDependency[] = []; + + try { + const ast = babelParser.parse(fs.readFileSync(file, 'utf-8'), { + // Support JSX and TS + plugins: ['typescript', 'jsx'], + sourceType: 'module', + }); + + traverse(ast, { + ImportDeclaration(path) { + const { node } = path; + if (/\.css$/i.test(node.source.value)) { + StyleDependencies.push({ + source: node.source.value, + // Just return first identifier. + identifier: node.specifiers[0] ? node.specifiers[0].local.name : null + }); + } + } + }); + } catch (e) { + // ignore + } + + return StyleDependencies; +}; diff --git a/extensions/iceworks-style-helper/src/styleInfoViewer/findStyleSelectors.ts b/extensions/iceworks-style-helper/src/styleInfoViewer/findStyleSelectors.ts new file mode 100644 index 000000000..722afd495 --- /dev/null +++ b/extensions/iceworks-style-helper/src/styleInfoViewer/findStyleSelectors.ts @@ -0,0 +1,23 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import css from 'css'; +import { IStyle } from './findStyle'; +import { IStyleDependency } from './findStyleDependencies'; + +// Find styles selectors, ['.wrap', '.header' ....] +export default function findStyleSelectors(directory: string, styleDependencies: IStyleDependency[] = []): string[] { + let selectors: string[] = []; + + for (let i = 0, l = styleDependencies.length; i < l; i++) { + const file = path.join(directory, styleDependencies[i].source); + const stylesheet = css.parse(fs.readFileSync(file, 'utf-8')).stylesheet; + + // eslint-disable-next-line + stylesheet.rules.forEach((rule: IStyle) => { + selectors = selectors.concat(rule.selectors); + }); + } + + return selectors; +}; + diff --git a/extensions/iceworks-style-helper/src/styleInfoViewer/index.ts b/extensions/iceworks-style-helper/src/styleInfoViewer/index.ts new file mode 100644 index 000000000..480d45f6b --- /dev/null +++ b/extensions/iceworks-style-helper/src/styleInfoViewer/index.ts @@ -0,0 +1,93 @@ +import * as vscode from 'vscode'; +import { findStyle, IStylePosition } from './findStyle'; +import { findStyleDependencies } from './findStyleDependencies'; +import findStyleSelectors from './findStyleSelectors'; +import { getFocusCodeInfo } from '../getFocusCodeInfo'; + +const SUPPORT_LANGUAGES = [ + 'javascript', + 'javascriptreact', + 'typescript', + 'typescriptreact' +]; + +// Cmd+Click jump to style definition +function provideDefinition(document: vscode.TextDocument, position: vscode.Position) { + const { line, word, fileName, directory } = getFocusCodeInfo(document, position); + + if (!/style|className/g.test(line.text)) return; + + const matched = findStyle(directory, word, findStyleDependencies(fileName)); + if (matched) { + const matchedPosition: IStylePosition = matched.position; + return new vscode.Location( + vscode.Uri.file(matched.file), + // The zero-based line and character value. + new vscode.Position(matchedPosition.start.line - 1, matchedPosition.start.column - 1) + ); + } +} + +// Show current style on hover over +function provideHover(document: vscode.TextDocument, position: vscode.Position) { + const { line, word, fileName, directory } = getFocusCodeInfo(document, position); + + if (!/style|className/g.test(line.text)) return; + + const matched = findStyle(directory, word, findStyleDependencies(fileName)); + if (matched) { + // Markdown css code + return new vscode.Hover(`\`\`\`css \n ${matched.code} \n \`\`\`\``); + } +} + +// Styles auto Complete +function provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) { + const { line, fileName, directory } = getFocusCodeInfo(document, position); + if (!/style|className/g.test(line.text)) return; + + // In case of cursor shaking + const word = line.text.substring(0, position.character); + const styleDependencies = findStyleDependencies(fileName); + + for (let i = 0, l = styleDependencies.length; i < l; i++) { + if (styleDependencies[i].identifier && new RegExp(`${styleDependencies[i].identifier}\\.$`).test(word)) { + return findStyleSelectors(directory, styleDependencies).map((selector: string) => { + // Remove class selector `.`, When use styles.xxx. + return new vscode.CompletionItem(selector.replace('.', ''), vscode.CompletionItemKind.Variable); + }); + } + } +} + +export default function styleInfoViewer(context: vscode.ExtensionContext) { + // Cmd+Click jump to style definition + context.subscriptions.push( + vscode.languages.registerDefinitionProvider( + SUPPORT_LANGUAGES, + { provideDefinition } + ) + ); + + SUPPORT_LANGUAGES.forEach((language) => { + // Show current style on hover over + context.subscriptions.push( + vscode.languages.registerHoverProvider( + language, + { provideHover } + ) + ); + + // Styles auto Complete + context.subscriptions.push( + vscode.languages.registerCompletionItemProvider( + language, + { provideCompletionItems }, + // match [styles identifier].xxx + // Example: `import test from './xxx.css'` match test.xxx; + '.' + ) + ); + }); +} + From 19ecd4f385eb62851ea80b82588b8c909706967a Mon Sep 17 00:00:00 2001 From: Hengchang Lu <44047106+luhc228@users.noreply.github.com> Date: Thu, 25 Jun 2020 19:44:51 +0800 Subject: [PATCH 2/8] chore: link-project-creator-registry (#132) --- packages/project-service/package.json | 4 ++-- packages/project-service/src/index.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/project-service/package.json b/packages/project-service/package.json index f286e60b2..998ac7b30 100644 --- a/packages/project-service/package.json +++ b/packages/project-service/package.json @@ -1,6 +1,6 @@ { "name": "@iceworks/project-service", - "version": "0.1.7", + "version": "0.1.8", "description": "Iceworks project service for VSCode extension.", "files": [ "lib" @@ -23,4 +23,4 @@ "access": "public" }, "gitHead": "fc5b35f95ab4cc24898845916acf598c2f34d576" -} +} \ No newline at end of file diff --git a/packages/project-service/src/index.ts b/packages/project-service/src/index.ts index 3043ad957..8eab1857c 100644 --- a/packages/project-service/src/index.ts +++ b/packages/project-service/src/index.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import * as fsExtra from 'fs-extra'; import { downloadAndGenerateProject } from '@iceworks/generate-project'; import { IMaterialScaffold } from '@iceworks/material-utils'; -import { checkPathExists } from '@iceworks/common-service'; +import { checkPathExists, getDataFromSettingJson, CONFIGURATION_KEY_NPM_REGISTRY } from '@iceworks/common-service'; import { readPackageJSON } from 'ice-npm-utils'; import * as simpleGit from 'simple-git/promise'; import * as path from 'path'; @@ -93,7 +93,8 @@ export async function createProject(data): Promise { if (isProjectDirExists) { throw new Error(`文件夹「${projectDir}」已存在,请重新输入项目名称。`) } - const { npm, registry, version } = scaffold.source; + const { npm, version } = scaffold.source; + const registry = getDataFromSettingJson(CONFIGURATION_KEY_NPM_REGISTRY); await downloadAndGenerateProject(projectDir, npm, version, registry); return projectDir; } From edede3279cd3b5b0af51509230546a3a909a09d7 Mon Sep 17 00:00:00 2001 From: Hengchang Lu <44047106+luhc228@users.noreply.github.com> Date: Sun, 28 Jun 2020 14:30:28 +0800 Subject: [PATCH 3/8] feat: config helper (#130) * feat: init config helper * refactor: tree provider & webview * feat: config helper * feat: add material operation function * fix: extensionDependencies * chore: rename display name * chore: version * fix: fix by the comment * fix: material-service * feat: update setting entrys * chore: remove code * fix: fix by the comments --- extensions/iceworks-app/.vscodeignore | 1 + extensions/iceworks-app/package.json | 51 +++---- extensions/iceworks-app/package.nls.json | 5 +- .../iceworks-app/package.nls.zh-cn.json | 5 +- extensions/iceworks-app/src/extension.ts | 107 +++++--------- extensions/iceworks-app/src/services.ts | 4 + .../iceworks-app/src/views/componentsView.ts | 15 +- .../src/views/nodeDependenciesView.ts | 29 +++- .../iceworks-app/src/views/npmScriptsView.ts | 14 +- .../iceworks-app/src/views/pagesView.ts | 13 +- extensions/iceworks-app/web/build.json | 33 +++++ .../mocks/common/getDataFromSettingJson.json | 0 extensions/iceworks-app/web/package.json | 36 +++++ .../iceworks-app/web/public/assets/delete.svg | 1 + .../iceworks-app/web/public/assets/edit.svg | 1 + .../iceworks-app/web/public/favicon.png | Bin 0 -> 4943 bytes extensions/iceworks-app/web/public/index.html | 15 ++ extensions/iceworks-app/web/src/app.ts | 9 ++ .../iceworks-app/web/src/callService.ts | 11 ++ extensions/iceworks-app/web/src/constants.ts | 10 ++ extensions/iceworks-app/web/src/global.scss | 4 + .../CustomMaterialSource.module.scss | 19 +++ .../ConfigHelper/CustomMaterialSource.tsx | 103 ++++++++++++++ .../MaterialSourceForm.module.scss | 17 +++ .../pages/ConfigHelper/MaterialSourceForm.tsx | 56 ++++++++ .../src/pages/ConfigHelper/index.module.scss | 10 ++ .../web/src/pages/ConfigHelper/index.tsx | 134 ++++++++++++++++++ extensions/iceworks-app/web/src/routes.ts | 10 ++ extensions/iceworks-app/web/src/typings.d.ts | 13 ++ extensions/iceworks-app/web/tsconfig.json | 27 ++++ .../iceworks-project-creator/package.json | 2 +- .../components/CreateDEFProjectForm/index.tsx | 1 - .../ScaffoldMarket/index.module.scss | 13 +- .../components/ScaffoldMarket/index.tsx | 73 ++++++---- .../src/pages/CreateProject/index.module.scss | 14 ++ .../web/src/pages/CreateProject/index.tsx | 16 ++- packages/common-service/package.json | 2 +- packages/common-service/src/index.ts | 40 +----- packages/material-service/package.json | 4 +- packages/material-service/src/index.ts | 65 ++++++++- 40 files changed, 789 insertions(+), 194 deletions(-) create mode 100644 extensions/iceworks-app/src/services.ts create mode 100644 extensions/iceworks-app/web/build.json create mode 100644 extensions/iceworks-app/web/mocks/common/getDataFromSettingJson.json create mode 100644 extensions/iceworks-app/web/package.json create mode 100644 extensions/iceworks-app/web/public/assets/delete.svg create mode 100644 extensions/iceworks-app/web/public/assets/edit.svg create mode 100644 extensions/iceworks-app/web/public/favicon.png create mode 100644 extensions/iceworks-app/web/public/index.html create mode 100644 extensions/iceworks-app/web/src/app.ts create mode 100644 extensions/iceworks-app/web/src/callService.ts create mode 100644 extensions/iceworks-app/web/src/constants.ts create mode 100644 extensions/iceworks-app/web/src/global.scss create mode 100644 extensions/iceworks-app/web/src/pages/ConfigHelper/CustomMaterialSource.module.scss create mode 100644 extensions/iceworks-app/web/src/pages/ConfigHelper/CustomMaterialSource.tsx create mode 100644 extensions/iceworks-app/web/src/pages/ConfigHelper/MaterialSourceForm.module.scss create mode 100644 extensions/iceworks-app/web/src/pages/ConfigHelper/MaterialSourceForm.tsx create mode 100644 extensions/iceworks-app/web/src/pages/ConfigHelper/index.module.scss create mode 100644 extensions/iceworks-app/web/src/pages/ConfigHelper/index.tsx create mode 100644 extensions/iceworks-app/web/src/routes.ts create mode 100644 extensions/iceworks-app/web/src/typings.d.ts create mode 100644 extensions/iceworks-app/web/tsconfig.json diff --git a/extensions/iceworks-app/.vscodeignore b/extensions/iceworks-app/.vscodeignore index 1cc773668..22e8d358c 100644 --- a/extensions/iceworks-app/.vscodeignore +++ b/extensions/iceworks-app/.vscodeignore @@ -7,3 +7,4 @@ src/** **/*.ts node_modules webpack.config.js +web/** \ No newline at end of file diff --git a/extensions/iceworks-app/package.json b/extensions/iceworks-app/package.json index ae01c1877..e4b786ada 100644 --- a/extensions/iceworks-app/package.json +++ b/extensions/iceworks-app/package.json @@ -1,9 +1,9 @@ { "name": "iceworks-app", - "displayName": "Iceworks App", - "description": "Universal Application Development Extension.", + "displayName": "Iceworks Project Viewer", + "description": "Quick view your Universal Application project(React/Rax/Vue, etc).", "publisher": "iceworks-team", - "version": "0.1.31", + "version": "0.1.32", "engines": { "vscode": "^1.41.0" }, @@ -15,7 +15,8 @@ "onView:nodeDependencies", "onView:scripts", "onView:pages", - "onView:components" + "onView:components", + "onCommand:iceworksApp.configHelper.start" ], "main": "./build/extension.js", "contributes": { @@ -23,7 +24,7 @@ "activitybar": [ { "id": "iceworksApp", - "title": "Iceworks App", + "title": "Iceworks", "icon": "assets/sidebar-logo.png" } ] @@ -32,7 +33,7 @@ "iceworksApp": [ { "id": "welcome", - "name": "%iceworksApp.view.welcome.name%", + "name": "", "when": "workbenchState == empty || iceworks:isNotTargetProject" }, { @@ -80,6 +81,10 @@ } ], "commands": [ + { + "command": "iceworksApp.configHelper.start", + "title": "Iceworks: Set Iceworks Configuration" + }, { "command": "iceworksApp.npmScripts.refresh", "title": "%iceworksApp.npmScripts.refresh.title%", @@ -132,22 +137,6 @@ "dark": "assets/dark/refresh.svg" } }, - { - "command": "iceworksApp.nodeDependencies.setPackageManager", - "title": "%iceworksApp.nodeDependencies.setPackageManager.title%", - "icon": { - "light": "assets/light/setting.svg", - "dark": "assets/dark/setting.svg" - } - }, - { - "command": "iceworksApp.nodeDependencies.setNpmRegistry", - "title": "%iceworksApp.nodeDependencies.setNpmRegistry.title%", - "icon": { - "light": "assets/light/registry.svg", - "dark": "assets/dark/registry.svg" - } - }, { "command": "iceworksApp.nodeDependencies.addDepsAndDevDeps", "title": "%iceworksApp.nodeDependencies.addDepsAndDevDeps.title%", @@ -224,16 +213,6 @@ "when": "view == components", "group": "navigation" }, - { - "command": "iceworksApp.nodeDependencies.setPackageManager", - "when": "view == nodeDependencies", - "group": "navigation@21" - }, - { - "command": "iceworksApp.nodeDependencies.setNpmRegistry", - "when": "view == nodeDependencies", - "group": "navigation@22" - }, { "command": "iceworksApp.nodeDependencies.addDepsAndDevDeps", "when": "view == nodeDependencies", @@ -274,7 +253,7 @@ ] }, "configuration": { - "title": "Iceworks App", + "title": "Iceworks", "properties": { "iceworks.packageManager": { "type": "string", @@ -304,7 +283,9 @@ "url": "https://github.com/ice-lab/iceworks.git" }, "scripts": { - "vscode:prepublish": "rm -rf build && webpack --mode production", + "vscode:prepublish": "rm -rf build && npm run build:web && webpack --mode production", + "build:web": "cd web && npm run build", + "watch:web": "cd web && npm run start", "webpack": "webpack --mode development", "webpack-dev": "webpack --mode development --watch", "compile": "tsc -p ./tsconfig.json" @@ -321,7 +302,9 @@ }, "dependencies": { "@iceworks/common-service": "^0.1.4", + "@iceworks/material-service": "^0.1.5", "@iceworks/project-service": "^0.1.6", + "@iceworks/vscode-webview": "^0.1.2", "fs-extra": "^9.0.0", "ice-npm-utils": "^2.0.0", "latest-version": "^5.1.0", diff --git a/extensions/iceworks-app/package.nls.json b/extensions/iceworks-app/package.nls.json index 9addc67de..6cc7910af 100644 --- a/extensions/iceworks-app/package.nls.json +++ b/extensions/iceworks-app/package.nls.json @@ -1,10 +1,9 @@ { - "iceworksApp.view.welcome.name": "Welcome", "iceworksApp.view.npmScripts.name": "npm Scripts", "iceworksApp.view.pages.name": "Pages", "iceworksApp.view.components.name": "Components", "iceworksApp.view.nodeDependencies.name": "Node Dependencies", - "iceworksApp.viewsWelcome.welcome.contents": "To use Iceworks App, you need to open a folder or create a new project first. \n[Open a Folder](command:vscode.openFolder)\n[Create New Project](command:iceworks-project-creator.start)\nRead the [docs](https://marketplace.visualstudio.com/items?itemName=iceworks-team.iceworks) to learn more about how to use Iceworks App in VS Code.", + "iceworksApp.viewsWelcome.welcome.contents": "To use Iceworks App, you need to open a folder or create a new project first. \n[Open a Folder](command:vscode.openFolder)\n[Create New Project](command:iceworks-project-creator.start)\n[Iceworks Configuration](command:iceworksApp.configHelper.start)\nRead the [docs](https://marketplace.visualstudio.com/items?itemName=iceworks-team.iceworks) to learn more about how to use Iceworks App in VS Code.", "iceworksApp.viewsWelcome.npmScripts.contents": "npm scripts could not be found in package.json.", "iceworksApp.viewsWelcome.pages.contents": "Pages could not be found.", "iceworksApp.viewsWelcome.components.contents": "Components could not be found.", @@ -16,8 +15,6 @@ "iceworksApp.pages.openFile.title": "Open File", "iceworksApp.components.add.title": "Add Components", "iceworksApp.components.refresh.title": "Refresh", - "iceworksApp.nodeDependencies.setPackageManager.title": "Set npm Package Manager", - "iceworksApp.nodeDependencies.setNpmRegistry.title": "Set npm Registry", "iceworksApp.nodeDependencies.addDepsAndDevDeps.title": "Add Dependencies", "iceworksApp.nodeDependencies.dependencies.add.title": "Add Dependency", "iceworksApp.nodeDependencies.devDependencies.add.title": "Add DevDependency", diff --git a/extensions/iceworks-app/package.nls.zh-cn.json b/extensions/iceworks-app/package.nls.zh-cn.json index 07762dfc0..2a652bc5c 100644 --- a/extensions/iceworks-app/package.nls.zh-cn.json +++ b/extensions/iceworks-app/package.nls.zh-cn.json @@ -1,10 +1,9 @@ { - "iceworksApp.view.welcome.name": "欢迎", "iceworksApp.view.npmScripts.name": "npm 脚本", "iceworksApp.view.pages.name": "页面列表", "iceworksApp.view.components.name": "组件列表", "iceworksApp.view.nodeDependencies.name": "依赖列表", - "iceworksApp.viewsWelcome.welcome.contents": "要使用 Iceworks App,你需要先打开一个文件夹或创建一个新项目。\n[打开文件夹](command:vscode.openFolder)\n[创建新项目](command:iceworks-project-creator.start)\n查看[文档](https://marketplace.visualstudio.com/items?itemName=iceworks-team.iceworks)以学习如何在 VS Code 中如何使用 Iceworks App。", + "iceworksApp.viewsWelcome.welcome.contents": "要使用 Iceworks App,你需要先打开一个文件夹或创建一个新项目。\n[打开文件夹](command:vscode.openFolder)\n[创建新项目](command:iceworks-project-creator.start)\n[Iceworks 设置](command:iceworksApp.configHelper.start)\n查看[文档](https://marketplace.visualstudio.com/items?itemName=iceworks-team.iceworks)以学习如何在 VS Code 中如何使用 Iceworks App。", "iceworksApp.viewsWelcome.npmScripts.contents": "没找到 npm 脚本。", "iceworksApp.viewsWelcome.pages.contents": "没找到页面。", "iceworksApp.viewsWelcome.components.contents": "没找到组件。", @@ -16,8 +15,6 @@ "iceworksApp.pages.openFile.title": "打开文件", "iceworksApp.components.add.title": "添加组件", "iceworksApp.components.refresh.title": "刷新", - "iceworksApp.nodeDependencies.setPackageManager.title": "设置npm包管理工具", - "iceworksApp.nodeDependencies.setNpmRegistry.title": "设置npm镜像源", "iceworksApp.nodeDependencies.addDepsAndDevDeps.title": "添加依赖", "iceworksApp.nodeDependencies.dependencies.add.title": "添加dependency", "iceworksApp.nodeDependencies.devDependencies.add.title": "添加devDependency", diff --git a/extensions/iceworks-app/src/extension.ts b/extensions/iceworks-app/src/extension.ts index 31a86ce65..0081688a6 100644 --- a/extensions/iceworks-app/src/extension.ts +++ b/extensions/iceworks-app/src/extension.ts @@ -1,34 +1,23 @@ import * as vscode from 'vscode'; -import { Terminal } from 'vscode'; -import * as path from 'path'; +import { Terminal, window, ViewColumn } from 'vscode'; +import { connectService, getHtmlForWebview } from '@iceworks/vscode-webview/lib/vscode'; import { getProjectType } from '@iceworks/project-service'; -import { setPackageManager, setNpmRegistry, getPackageManagersDefaultFromPackageJson, getNpmRegistriesDefaultFromPckageJson, initExtensionConfiguration, Logger } from '@iceworks/common-service'; -import { NpmScriptsProvider, Script } from './views/npmScriptsView'; -import { DepNodeProvider, DependencyNode, addDepCommandHandler, showDepInputBox } from './views/nodeDependenciesView'; -import { ComponentsProvider } from './views/componentsView'; -import { PagesProvider } from './views/pagesView'; +import { initExtensionConfiguration, Logger } from '@iceworks/common-service'; +import { createNpmScriptsTreeProvider } from './views/npmScriptsView'; +import { createNodeDependenciesTreeProvider } from './views/nodeDependenciesView'; +import { createComponentsTreeProvider } from './views/componentsView'; +import { createPagesTreeProvider } from './views/pagesView'; import { ITerminalMap } from './types'; -import { openEntryFile, executeCommand } from './utils'; +import services from './services'; // eslint-disable-next-line const { name, version } = require('../package.json'); export async function activate(context: vscode.ExtensionContext) { - const { globalState } = context; + const { globalState, subscriptions, extensionPath } = context; const rootPath = vscode.workspace.rootPath; - - if (!rootPath) { - vscode.window.showInformationMessage('当前工作区为空,请打开项目或新建项目。'); - vscode.commands.executeCommand('setContext', 'iceworks:isNotTargetProject', true); - return; - } - try { - const projectType = await getProjectType(); - vscode.commands.executeCommand('setContext', 'iceworks:isNotTargetProject', projectType === 'unknown'); - } catch (e) { - vscode.commands.executeCommand('setContext', 'iceworks:isNotTargetProject', true); - } - + // auto set configuration + initExtensionConfiguration(globalState); // data collection const logger = new Logger(name, globalState); logger.recordDAU(); @@ -39,53 +28,35 @@ export async function activate(context: vscode.ExtensionContext) { version, } }); + // init webview + function activeWebview() { + const webviewPanel: vscode.WebviewPanel = window.createWebviewPanel('iceworks', '设置面板', ViewColumn.One, { + enableScripts: true, + retainContextWhenHidden: true, + }); + webviewPanel.webview.html = getHtmlForWebview(extensionPath); + connectService(webviewPanel.webview, subscriptions, { services, logger }); + } - // auto set configuration - initExtensionConfiguration(globalState); + subscriptions.push(vscode.commands.registerCommand('iceworksApp.configHelper.start', function () { + activeWebview(); + })); + if (!rootPath) { + vscode.window.showInformationMessage('当前工作区为空,请打开项目或新建项目。'); + vscode.commands.executeCommand('setContext', 'iceworks:isNotTargetProject', true); + return; + } + try { + const projectType = await getProjectType(); + vscode.commands.executeCommand('setContext', 'iceworks:isNotTargetProject', projectType === 'unknown'); + } catch (e) { + vscode.commands.executeCommand('setContext', 'iceworks:isNotTargetProject', true); + } const terminals: ITerminalMap = new Map(); - - vscode.window.onDidCloseTerminal(term => terminals.delete(term.name)); - - const npmScriptsProvider = new NpmScriptsProvider(context, rootPath); - vscode.window.registerTreeDataProvider('npmScripts', npmScriptsProvider); - vscode.commands.registerCommand('iceworksApp.npmScripts.executeCommand', (script: Script) => executeCommand(terminals, script.command!)); - vscode.commands.registerCommand('iceworksApp.npmScripts.refresh', () => npmScriptsProvider.refresh()); - - const componentsProvider = new ComponentsProvider(context, rootPath); - vscode.window.registerTreeDataProvider('components', componentsProvider); - vscode.commands.registerCommand('iceworksApp.components.add', () => { - console.log('iceworksApp: activate iceworks-component-builder.generate'); - vscode.commands.executeCommand('iceworks-component-builder.generate'); - }); - vscode.commands.registerCommand('iceworksApp.components.refresh', () => componentsProvider.refresh()); - vscode.commands.registerCommand('iceworksApp.components.openFile', (p) => openEntryFile(p)); - - const pagesProvider = new PagesProvider(context, rootPath); - vscode.window.registerTreeDataProvider('pages', pagesProvider); - vscode.commands.registerCommand('iceworksApp.pages.add', () => { - console.log('iceworksApp: activate iceworks-page-builder.create'); - vscode.commands.executeCommand('iceworks-page-builder.create'); - }); - vscode.commands.registerCommand('iceworksApp.pages.refresh', () => pagesProvider.refresh()); - vscode.commands.registerCommand('iceworksApp.pages.openFile', (p) => openEntryFile(p)); - - const nodeDependenciesProvider = new DepNodeProvider(context, rootPath); - vscode.window.registerTreeDataProvider('nodeDependencies', nodeDependenciesProvider); - vscode.commands.registerCommand('iceworksApp.nodeDependencies.refresh', () => nodeDependenciesProvider.refresh()); - vscode.commands.registerCommand('iceworksApp.nodeDependencies.upgrade', (node: DependencyNode) => executeCommand(terminals, node.command!)); - vscode.commands.registerCommand('iceworksApp.nodeDependencies.reinstall', async () => { - if (nodeDependenciesProvider.packageJsonExists()) { - const script = await nodeDependenciesProvider.getReinstallScript(); - executeCommand(terminals, script!); - } - }); - - const packageJsonPath: string = path.join(__filename, '..', '..', 'package.json'); - - context.subscriptions.push(vscode.commands.registerCommand('iceworksApp.nodeDependencies.dependencies.add', () => showDepInputBox(terminals, nodeDependenciesProvider, 'dependencies'))); - context.subscriptions.push(vscode.commands.registerCommand('iceworksApp.nodeDependencies.devDependencies.add', () => showDepInputBox(terminals, nodeDependenciesProvider, 'devDependencies'))); - context.subscriptions.push(vscode.commands.registerCommand('iceworksApp.nodeDependencies.addDepsAndDevDeps', () => addDepCommandHandler(terminals, nodeDependenciesProvider))); - context.subscriptions.push(vscode.commands.registerCommand('iceworksApp.nodeDependencies.setPackageManager', () => setPackageManager(getPackageManagersDefaultFromPackageJson(packageJsonPath)))); - context.subscriptions.push(vscode.commands.registerCommand('iceworksApp.nodeDependencies.setNpmRegistry', () => setNpmRegistry(getNpmRegistriesDefaultFromPckageJson(packageJsonPath)))); + // init tree data providers + createNpmScriptsTreeProvider(context, rootPath, terminals); + createComponentsTreeProvider(context, rootPath); + createPagesTreeProvider(context, rootPath); + createNodeDependenciesTreeProvider(context, rootPath, terminals); } diff --git a/extensions/iceworks-app/src/services.ts b/extensions/iceworks-app/src/services.ts new file mode 100644 index 000000000..f3079aff7 --- /dev/null +++ b/extensions/iceworks-app/src/services.ts @@ -0,0 +1,4 @@ +import * as common from '@iceworks/common-service'; +import * as material from '@iceworks/material-service'; + +export default { common, material }; \ No newline at end of file diff --git a/extensions/iceworks-app/src/views/componentsView.ts b/extensions/iceworks-app/src/views/componentsView.ts index a1de457c3..26c051232 100644 --- a/extensions/iceworks-app/src/views/componentsView.ts +++ b/extensions/iceworks-app/src/views/componentsView.ts @@ -1,9 +1,9 @@ import * as vscode from 'vscode'; import * as fse from 'fs-extra'; import * as path from 'path'; -import { pathExists } from '../utils'; +import { pathExists, openEntryFile } from '../utils'; -export class ComponentsProvider implements vscode.TreeDataProvider { +class ComponentsProvider implements vscode.TreeDataProvider { private workspaceRoot: string; private extensionContext: vscode.ExtensionContext; @@ -80,3 +80,14 @@ class Component extends vscode.TreeItem { contextValue = 'component'; } + +export function createComponentsTreeProvider(context: vscode.ExtensionContext, rootPath: string) { + const componentsProvider = new ComponentsProvider(context, rootPath); + vscode.window.registerTreeDataProvider('components', componentsProvider); + vscode.commands.registerCommand('iceworksApp.components.add', () => { + console.log('iceworksApp: activate iceworks-component-builder.generate'); + vscode.commands.executeCommand('iceworks-component-builder.generate'); + }); + vscode.commands.registerCommand('iceworksApp.components.refresh', () => componentsProvider.refresh()); + vscode.commands.registerCommand('iceworksApp.components.openFile', (p) => openEntryFile(p)); +} \ No newline at end of file diff --git a/extensions/iceworks-app/src/views/nodeDependenciesView.ts b/extensions/iceworks-app/src/views/nodeDependenciesView.ts index d51601184..25b242e58 100644 --- a/extensions/iceworks-app/src/views/nodeDependenciesView.ts +++ b/extensions/iceworks-app/src/views/nodeDependenciesView.ts @@ -5,14 +5,18 @@ import * as util from 'util'; import * as path from 'path'; import latestVersion from 'latest-version'; import { getPackageLocalVersion } from 'ice-npm-utils'; -import { getDataFromSettingJson, createNpmCommand } from '@iceworks/common-service'; +import { + getDataFromSettingJson, + createNpmCommand, +} from '@iceworks/common-service'; import { pathExists, executeCommand } from '../utils'; import { NodeDepTypes, ITerminalMap } from '../types'; import { nodeDepTypes } from '../constants'; + const rimrafAsync = util.promisify(rimraf); -export class DepNodeProvider implements vscode.TreeDataProvider { +class DepNodeProvider implements vscode.TreeDataProvider { private workspaceRoot: string; private extensionContext: vscode.ExtensionContext; @@ -143,7 +147,7 @@ export class DepNodeProvider implements vscode.TreeDataProvider } } -export class DependencyNode extends vscode.TreeItem { +class DependencyNode extends vscode.TreeItem { constructor( public readonly extensionContext: vscode.ExtensionContext, public readonly label: string, @@ -173,6 +177,23 @@ export class DependencyNode extends vscode.TreeItem { }; } +export function createNodeDependenciesTreeProvider(context, rootPath, terminals) { + const nodeDependenciesProvider = new DepNodeProvider(context, rootPath); + vscode.window.registerTreeDataProvider('nodeDependencies', nodeDependenciesProvider); + vscode.commands.registerCommand('iceworksApp.nodeDependencies.refresh', () => nodeDependenciesProvider.refresh()); + vscode.commands.registerCommand('iceworksApp.nodeDependencies.upgrade', (node: DependencyNode) => executeCommand(terminals, node.command!)); + vscode.commands.registerCommand('iceworksApp.nodeDependencies.reinstall', async () => { + if (nodeDependenciesProvider.packageJsonExists()) { + const script = await nodeDependenciesProvider.getReinstallScript(); + executeCommand(terminals, script!); + } + }); + + context.subscriptions.push(vscode.commands.registerCommand('iceworksApp.nodeDependencies.dependencies.add', () => showDepInputBox(terminals, nodeDependenciesProvider, 'dependencies'))); + context.subscriptions.push(vscode.commands.registerCommand('iceworksApp.nodeDependencies.devDependencies.add', () => showDepInputBox(terminals, nodeDependenciesProvider, 'devDependencies'))); + context.subscriptions.push(vscode.commands.registerCommand('iceworksApp.nodeDependencies.addDepsAndDevDeps', () => addDepCommandHandler(terminals, nodeDependenciesProvider))); +} + export function addDepCommandHandler(terminals: ITerminalMap, nodeDependenciesInstance: any) { const quickPick = vscode.window.createQuickPick(); quickPick.items = nodeDepTypes.map(label => ({ label, detail: `Install ${label}` })); @@ -186,7 +207,7 @@ export function addDepCommandHandler(terminals: ITerminalMap, nodeDependenciesIn quickPick.show(); }; -export async function showDepInputBox(terminals: ITerminalMap, nodeDependenciesInstance: any, depType: NodeDepTypes) { +async function showDepInputBox(terminals: ITerminalMap, nodeDependenciesInstance: any, depType: NodeDepTypes) { const result = await vscode.window.showInputBox({ placeHolder: 'Please input the module name you want to install. For example lodash / loadsh@latest', }); diff --git a/extensions/iceworks-app/src/views/npmScriptsView.ts b/extensions/iceworks-app/src/views/npmScriptsView.ts index bfcbe3130..886694e1b 100644 --- a/extensions/iceworks-app/src/views/npmScriptsView.ts +++ b/extensions/iceworks-app/src/views/npmScriptsView.ts @@ -2,7 +2,8 @@ import * as vscode from 'vscode'; import * as fse from 'fs-extra'; import * as path from 'path'; import { createNpmCommand } from '@iceworks/common-service' -import { pathExists } from '../utils'; +import { pathExists, executeCommand } from '../utils'; +import { ITerminalMap } from '../types'; export class NpmScriptsProvider implements vscode.TreeDataProvider