From 19381454ad959c53915e0393eac8c66047ce7a3b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 22 Jun 2017 19:36:53 -0700 Subject: [PATCH] Get find working as an addon --- demo/index.html | 1 + gulpfile.js | 29 ++++++++-- src/addons/search/search.ts | 56 +++++++++++++++++++ .../search/searchHelper.ts} | 8 +-- src/addons/search/tsconfig.json | 10 ++++ src/xterm.js | 25 +-------- 6 files changed, 98 insertions(+), 31 deletions(-) create mode 100644 src/addons/search/search.ts rename src/{SearchHelper.ts => addons/search/searchHelper.ts} (91%) create mode 100644 src/addons/search/tsconfig.json diff --git a/demo/index.html b/demo/index.html index d4574aa3..9546b697 100644 --- a/demo/index.html +++ b/demo/index.html @@ -10,6 +10,7 @@ +

xterm.js: xterm, in the browser

diff --git a/gulpfile.js b/gulpfile.js index 1f92e537..1dd49887 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,6 +14,7 @@ const ts = require('gulp-typescript'); let buildDir = process.env.BUILD_DIR || 'build'; let tsProject = ts.createProject('tsconfig.json'); +let tsProjectSearchAddon = ts.createProject('./src/addons/search/tsconfig.json'); let srcDir = tsProject.config.compilerOptions.rootDir; let outDir = tsProject.config.compilerOptions.outDir; @@ -30,13 +31,18 @@ gulp.task('tsc', function () { let tsResult = tsProject.src().pipe(sourcemaps.init()).pipe(tsProject()); let tsc = tsResult.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(outDir)); + fs.emptyDirSync(`${outDir}/addons`); + fs.emptyDirSync(`${outDir}/addons/search`); + let tsResultSearchAddon = tsProjectSearchAddon.src().pipe(sourcemaps.init()).pipe(tsProjectSearchAddon()); + let tscSearchAddon = tsResultSearchAddon.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(`${outDir}/addons/search`)); + // Copy all addons from ${srcDir}/ to ${outDir}/ - let copyAddons = gulp.src(`${srcDir}/addons/**/*`).pipe(gulp.dest(`${outDir}/addons`)); + let copyAddons = gulp.src([`${srcDir}/addons/**/*`, `!${srcDir}/addons/search`, `!${srcDir}/addons/search/**`]).pipe(gulp.dest(`${outDir}/addons`)); // Copy stylesheets from ${srcDir}/ to ${outDir}/ let copyStylesheets = gulp.src(`${srcDir}/**/*.css`).pipe(gulp.dest(outDir)); - return merge(tsc, copyAddons, copyStylesheets); + return merge(tsc, tscSearchAddon, copyAddons, copyStylesheets); }); /** @@ -63,13 +69,28 @@ gulp.task('browserify', ['tsc'], function() { .pipe(sourcemaps.write('./')) .pipe(gulp.dest(buildDir)); + let browserifyOptionsSearchAddon = { + basedir: buildDir, + debug: true, + entries: [`../${outDir}/addons/search/search.js`], + cache: {}, + packageCache: {} + }; + let bundleStreamSearchAddon = browserify(browserifyOptionsSearchAddon) + .bundle() + .pipe(source('./addons/search/search.js')) + .pipe(buffer()) + .pipe(sourcemaps.init({loadMaps: true, sourceRoot: '..'})) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(buildDir)); + // Copy all add-ons from ${outDir}/ to buildDir - let copyAddons = gulp.src(`${outDir}/addons/**/*`).pipe(gulp.dest(`${buildDir}/addons`)); + let copyAddons = gulp.src([`${outDir}/addons/**/*`, `!${outDir}/addons/search`, `!${outDir}/addons/search/**`]).pipe(gulp.dest(`${buildDir}/addons`)); // Copy stylesheets from ${outDir}/ to ${buildDir}/ let copyStylesheets = gulp.src(`${outDir}/**/*.css`).pipe(gulp.dest(buildDir)); - return merge(bundleStream, copyAddons, copyStylesheets); + return merge(bundleStream, bundleStreamSearchAddon, copyAddons, copyStylesheets); }); gulp.task('instrument-test', function () { diff --git a/src/addons/search/search.ts b/src/addons/search/search.ts new file mode 100644 index 00000000..b049eba7 --- /dev/null +++ b/src/addons/search/search.ts @@ -0,0 +1,56 @@ +/** + * @license MIT + */ + +import { SearchHelper } from './SearchHelper'; + +declare var exports: any; +declare var module: any; +declare var define: any; +declare var require: any; + +(function (addon) { + if ('Terminal' in window) { + /* + * Plain browser environment + */ + addon((window).Terminal); + } else if (typeof define == 'function') { + /* + * Require.js is available + */ + define(['../../xterm'], addon); + } else if (typeof exports === 'object' && typeof module === 'object') { + /* + * CommonJS environment + */ + var xterm = '../../xterm'; // Put in a variable do it's not pulled in by browserify + module.exports = addon(require(xterm)); + } +})((Terminal: any) => { + /** + * Find the next instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The term to search for. + * @return Whether a result was found. + */ + Terminal.prototype.findNext = function(term: string): boolean { + if (!this._searchHelper) { + this.searchHelper = new SearchHelper(this, Terminal.translateBufferLineToString); + } + return (this.searchHelper).findNext(term); + }; + + /** + * Find the previous instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The term to search for. + * @return Whether a result was found. + */ + Terminal.prototype.findPrevious = function(term: string): boolean { + if (!this._searchHelper) { + this.searchHelper = new SearchHelper(this, Terminal.translateBufferLineToString); + } + return (this.searchHelper).findPrevious(term); + }; +}); diff --git a/src/SearchHelper.ts b/src/addons/search/searchHelper.ts similarity index 91% rename from src/SearchHelper.ts rename to src/addons/search/searchHelper.ts index 300daef6..6f88e04b 100644 --- a/src/SearchHelper.ts +++ b/src/addons/search/searchHelper.ts @@ -2,8 +2,8 @@ * @license MIT */ -import { ITerminal } from './Interfaces'; -import { translateBufferLineToString } from './utils/BufferLine'; +// import { ITerminal } from '../../Interfaces'; +// import { translateBufferLineToString } from '../../utils/BufferLine'; interface ISearchResult { term: string; @@ -12,7 +12,7 @@ interface ISearchResult { } export class SearchHelper { - constructor(private _terminal: ITerminal) { + constructor(private _terminal: any, private _translateBufferLineToString: any) { // TODO: Search for multiple instances on 1 line // TODO: Don't use the actual selection, instead use a "find selection" so multiple instances can be highlighted // TODO: Highlight other instances in the viewport @@ -103,7 +103,7 @@ export class SearchHelper { private _findInLine(term: string, y: number): ISearchResult { const bufferLine = this._terminal.lines.get(y); - const lowerStringLine = translateBufferLineToString(bufferLine, true).toLowerCase(); + const lowerStringLine = this._translateBufferLineToString(bufferLine, true).toLowerCase(); const lowerTerm = term.toLowerCase(); const searchIndex = lowerStringLine.indexOf(lowerTerm); if (searchIndex >= 0) { diff --git a/src/addons/search/tsconfig.json b/src/addons/search/tsconfig.json new file mode 100644 index 00000000..f20bdf3d --- /dev/null +++ b/src/addons/search/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "rootDir": ".", + "outDir": "./c", + "sourceMap": true, + "removeComments": true + } +} diff --git a/src/xterm.js b/src/xterm.js index b485069a..dc57cc21 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -21,12 +21,12 @@ import { Parser } from './Parser'; import { Renderer } from './Renderer'; import { Linkifier } from './Linkifier'; import { SelectionManager } from './SelectionManager'; -import { SearchHelper } from './SearchHelper'; import { CharMeasure } from './utils/CharMeasure'; import * as Browser from './utils/Browser'; import * as Mouse from './utils/Mouse'; import { CHARSETS } from './Charsets'; import { getRawByteCoords } from './utils/Mouse'; +import { translateBufferLineToString } from './utils/BufferLine'; /** * Terminal Emulation References: @@ -224,7 +224,6 @@ function Terminal(options) { this.renderer = this.renderer || null; this.selectionManager = this.selectionManager || null; this.linkifier = this.linkifier || new Linkifier(); - this.searchHelper = this.searchHelper || null; // user input states this.writeBuffer = []; @@ -708,7 +707,6 @@ Terminal.prototype.open = function(parent, focus) { this.selectionManager.on('refresh', data => this.renderer.refreshSelection(data.start, data.end)); this.on('scroll', () => this.selectionManager.refresh()); this.viewportElement.addEventListener('scroll', () => this.selectionManager.refresh()); - this.searchHelper = new SearchHelper(this);; // Setup loop that draws to screen this.refresh(0, this.rows - 1); @@ -1408,26 +1406,6 @@ Terminal.prototype.selectAll = function() { this.selectionManager.selectAll(); } -/** - * Find the next instance of the term, then scroll to and select it. If it - * doesn't exist, do nothing. - * @param term The term to search for. - * @return Whether a result was found. - */ -Terminal.prototype.findNext = function(term) { - return this.searchHelper.findNext(term); -} - -/** - * Find the previous instance of the term, then scroll to and select it. If it - * doesn't exist, do nothing. - * @param term The term to search for. - * @return Whether a result was found. - */ -Terminal.prototype.findPrevious = function(term) { - return this.searchHelper.findPrevious(term); -} - /** * Handle a keydown event * Key Resources: @@ -2408,6 +2386,7 @@ function keys(obj) { * Expose */ +Terminal.translateBufferLineToString = translateBufferLineToString; Terminal.EventEmitter = EventEmitter; Terminal.inherits = inherits;