diff --git a/.gitignore b/.gitignore index ae6b74295..da632fc91 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ .DS_Store _Resharper.DefinitelyTyped +bin +obj +Properties diff --git a/ace/ace.d.ts b/ace/ace.d.ts index 75b597ba2..58d65ed4f 100644 --- a/ace/ace.d.ts +++ b/ace/ace.d.ts @@ -5,18 +5,96 @@ module AceAjax { - interface CommandManager { - addCommand(command); + export interface Delta { + action: string; + range: Range; + text: string; + lines: string[]; } - interface TextMode { + export interface EditorCommand { + + name:string; + + bindKey:any; + + exec:Function; + } + + export interface CommandManager { + + byName; + + commands; + + platform: string; + + addCommands(commands:EditorCommand[]); + + addCommand(command:EditorCommand); + + exec(name: string, editor: Editor, args: any); + } + + export interface Annotation { + + row: number; + + column: number; + + text: string; + + type: string; + } + + export interface TokenInfo { + + value: string; + } + + export interface Position { + + row: number; + + column: number; + } + + export interface KeyBinding { + + setDefaultHandler(kb); + + setKeyboardHandler(kb); + + addKeyboardHandler(kb, pos); + + removeKeyboardHandler(kb): bool; + + getKeyboardHandler(): any; + + onCommandKey(e, hashId, keyCode); + + onTextInput(text); + } + declare var KeyBinding: { + new(editor: Editor): KeyBinding; + } + + export interface TextMode { + getTokenizer(): any; + toggleCommentLines(state, doc, startRow, endRow); + getNextLineIndent (state, line, tab): string; + checkOutdent(state, line, input): bool; + autoOutdent(state, doc, row); + createWorker(session): any; + createModeDelegates (mapping); + transformAction(state, action, editor, session, param): any; } @@ -27,7 +105,7 @@ module AceAjax { /** * The main class required to set up an Ace instance in the browser. **/ - interface Ace { + export interface Ace { /** * Provides access to require in packed noconflict mode @@ -52,14 +130,14 @@ module AceAjax { * @param text {:textParam} * @param mode {:modeParam} **/ - createEditSession(text: Document, mode: TextMode): EditSession; + createEditSession(text: Document, mode: TextMode): IEditSession; /** * Creates a new [[EditSession]], and returns the associated [[Document]]. * @param text {:textParam} * @param mode {:modeParam} **/ - createEditSession(text: string, mode: TextMode): EditSession; + createEditSession(text: string, mode: TextMode): IEditSession; } //////////////// @@ -69,14 +147,14 @@ module AceAjax { /** * Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated. **/ - interface Anchor { + export interface Anchor { on(event: string, fn: (e) => any); /** * Returns an object identifying the `row` and `column` position of the current anchor. **/ - getPosition(): any; + getPosition(): Position; /** * Returns the current document. @@ -124,7 +202,9 @@ module AceAjax { * Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use. * If a certain row is changed, everything below that row is re-tokenized. **/ - interface BackgroundTokenizer { + export interface BackgroundTokenizer { + + states: any[]; /** * Sets a new tokenizer for this object. @@ -160,7 +240,7 @@ module AceAjax { * Gives list of tokens of the row. (tokens are cached) * @param row The row to get tokens at **/ - getTokens(row: number): any; + getTokens(row: number): TokenInfo[]; /** * [Returns the state of tokenization at the end of a row.]{: #BackgroundTokenizer.getState} @@ -185,7 +265,9 @@ module AceAjax { * Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s. * At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index. **/ - interface Document { + export interface Document { + + on(event: string, fn: (e) => any); /** * Replaces all the lines in the current `Document` with the value of `text`. @@ -261,20 +343,20 @@ module AceAjax { * @param position The position to start inserting at * @param text A chunk of text to insert **/ - insert(position: any, text: string): any; + insert(position: Position, text: string): any; /** * Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event. * @param row The index of the row to insert at * @param lines An array of strings **/ - insertLines(row: number, lines: Array): any; + insertLines(row: number, lines: string[]): any; /** * Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event. * @param position The position to insert at **/ - insertNewLine(position: any): any; + insertNewLine(position: Position): any; /** * Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event. @@ -320,12 +402,12 @@ module AceAjax { /** * Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`. **/ - applyDeltas(); + applyDeltas(deltas: Delta[]); /** * Reverts any changes previously applied. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`. **/ - revertDeltas(); + revertDeltas(deltas: Delta[]); /** * Converts an index position in a document to a `{row, column}` object. @@ -338,7 +420,7 @@ module AceAjax { * @param index An index to convert * @param startRow=0 The row from which to start the conversion **/ - indexToPosition(index: number, startRow: number): any; + indexToPosition(index: number, startRow: number): Position; /** * Converts the `{row, column}` position in a document to the character's index. @@ -351,7 +433,7 @@ module AceAjax { * @param pos The `{row, column}` to convert * @param startRow=0 The row from which to start the conversion **/ - positionToIndex(pos: any, startRow: number): number; + positionToIndex(pos: Position, startRow: number): number; } declare var Document: { /** @@ -374,11 +456,35 @@ module AceAjax { * Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state. * `EditSession` can be attached to only one [[Document `Document`]]. Same `Document` can be attached to several `EditSession`s. **/ - interface EditSession { + export interface IEditSession { + + selection: Selection; + + bgTokenizer: BackgroundTokenizer; + + doc: Document; on(event: string, fn: (e) => any); - selection: Selection; + findMatchingBracket(position: Position); + + addFold(text: string, range: Range); + + getFoldAt(row: number, column: number): any; + + removeFold(arg: any); + + expandFold(arg: any); + + unfold(arg1: any, arg2: bool); + + screenToDocumentColumn(row: number, column: number); + + getFoldDisplayLine(foldLine: any, docRow: number, docColumn: number): any; + + getFoldsInRange(range: Range): any; + + highlight(text: string); /** * Sets the `EditSession` to point to a new `Document`. If a `BackgroundTokenizer` exists, it also points to `doc`. @@ -425,14 +531,14 @@ module AceAjax { * Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows. * @param row The row to start at **/ - getTokens(row: number): any[]; + getTokens(row: number): TokenInfo[]; /** * Returns an object indicating the token at the current row. The object has two properties: `index` and `start`. * @param row The row number to retrieve from * @param column The column number to retrieve from **/ - getTokenAt(row: number, column: number): any; + getTokenAt(row: number, column: number): TokenInfo; /** * Sets the undo manager. @@ -579,7 +685,7 @@ module AceAjax { * Sets annotations for the `EditSession`. This functions emits the `'changeAnnotation'` event. * @param annotations A list of annotations **/ - setAnnotations(annotations: Array); + setAnnotations(annotations: Annotation[]); /** * Returns the annotations for the `EditSession`. @@ -704,7 +810,7 @@ module AceAjax { * @param position The position {row, column} to start inserting at * @param text A chunk of text to insert **/ - insert(position: any, text: string): any; + insert(position: Position, text: string): any; /** * Removes the `range` from the document. @@ -911,9 +1017,11 @@ module AceAjax { * @param text [If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text]{: #textParam} * @param mode [The inital language mode to use for the document]{: #modeParam} **/ - new(text: string, mode?: TextMode): EditSession; + new(text: string, mode?: TextMode): IEditSession; - new(text: string[]): EditSession; + new(content: string, mode?: string): IEditSession; + + new (text: string[], mode?: string): IEditSession; } //////////////////////////////// @@ -925,7 +1033,11 @@ module AceAjax { * The `Editor` manages the [[EditSession]] (which manages [[Document]]s), as well as the [[VirtualRenderer]], which draws everything to the screen. * Event sessions dealing with the mouse and keyboard are bubbled up from `Document` to the `Editor`, which decides what to do with them. **/ - interface Editor { + export interface Editor { + + inMultiSelectMode: bool; + + selectMoreLines(n: number); onTextInput(text: string); @@ -933,10 +1045,22 @@ module AceAjax { commands: CommandManager; - session: EditSession; + session: IEditSession; selection: Selection; + renderer: VirtualRenderer; + + keyBinding: KeyBinding; + + container: HTMLElement; + + onSelectionChange(e); + + onChangeMode(e?); + + execCommand(command:string, args?: any); + /** * Sets a new key handler, such as "vim" or "windows". * @param keyboardHandler The new key handler @@ -952,12 +1076,12 @@ module AceAjax { * Sets a new editsession to use. This method also emits the `'changeSession'` event. * @param session The new session to use **/ - setSession(session: EditSession); + setSession(session: IEditSession); /** * Returns the current session being used. **/ - getSession(): EditSession; + getSession(): IEditSession; /** * Sets the current document to `val`. @@ -1411,7 +1535,7 @@ module AceAjax { /** * Gets the current position of the cursor. **/ - getCursorPosition(): any; + getCursorPosition(): Position; /** * Returns the screen position of the cursor. @@ -1438,13 +1562,13 @@ module AceAjax { * @param row The new row number * @param column The new column number **/ - moveCursorTo(row: number, column: number); + moveCursorTo(row: number, column?: number, animate?:bool); /** * Moves the cursor to the position indicated by `pos.row` and `pos.column`. - * @param pos An object with two properties, row and column + * @param position An object with two properties, row and column **/ - moveCursorToPosition(pos: any); + moveCursorToPosition(position: Position); /** * Moves the cursor's row and column to the next matching bracket. @@ -1470,19 +1594,19 @@ module AceAjax { * Moves the cursor up in the document the specified number of times. Note that this does de-select the current selection. * @param times The number of times to change navigation **/ - navigateUp(times: number); + navigateUp(times?: number); /** * Moves the cursor down in the document the specified number of times. Note that this does de-select the current selection. * @param times The number of times to change navigation **/ - navigateDown(times: number); + navigateDown(times?: number); /** * Moves the cursor left in the document the specified number of times. Note that this does de-select the current selection. * @param times The number of times to change navigation **/ - navigateLeft(times: number); + navigateLeft(times?: number); /** * Moves the cursor right in the document the specified number of times. Note that this does de-select the current selection. @@ -1584,14 +1708,16 @@ module AceAjax { * @param renderer Associated `VirtualRenderer` that draws everything * @param session The `EditSession` to refer to **/ - new(renderer: VirtualRenderer, session: EditSession): Editor; + new(renderer: VirtualRenderer, session?: IEditSession): Editor; } //////////////////////////////// /// PlaceHolder //////////////////////////////// - interface PlaceHolder { + export interface PlaceHolder { + + on(event: string, fn: (e) => any); /** * PlaceHolder.setup() @@ -1637,16 +1763,39 @@ module AceAjax { } declare var PlaceHolder: { /** - * - session (Document): The document to associate with the anchor - * - length (Number): The starting row position - * - pos (Number): The starting column position - * - others (String): - * - mainClass (String): - * - othersClass (String): + * - @param session (Document): The document to associate with the anchor + * - @param length (Number): The starting row position + * - @param pos (Number): The starting column position + * - @param others (String): + * - @param mainClass (String): + * - @param othersClass (String): **/ - new(): PlaceHolder; + new (session: Document, length: number, pos: number, others: string, mainClass: string, othersClass: string): PlaceHolder; + + new (session: IEditSession, length: number, pos: Position, positions: Position[]): PlaceHolder; } + //////////////// + /// RangeList + //////////////// + + export interface IRangeList { + ranges: Range[]; + + pointIndex(pos: Position, startIndex?: number); + + addList(ranges: Range[]); + + add(ranges: Range); + + merge(): Range[]; + + substractPoint(pos: Position); + } + export var RangeList: { + new (): IRangeList; + } + //////////////// /// Range //////////////// @@ -1654,11 +1803,21 @@ module AceAjax { /** * This object is used in various places to indicate a region within the editor. To better visualize how this works, imagine a rectangle. Each quadrant of the rectangle is analogus to a range, as ranges contain a starting row and starting column, and an ending row, and ending column. **/ - interface Range { + export interface Range { - start: number; + startRow:number; - end: number; + startColumn:number; + + endRow:number; + + endColumn:number; + + start: Position; + + end: Position; + + isEmpty(): bool; /** * Returns `true` if and only if the starting row and column, and ending row and column, are equivalent to those given by `range`. @@ -1819,7 +1978,7 @@ module AceAjax { * Given the current `Range`, this function converts those starting and ending points into screen positions, and then returns a new `Range` object. * @param session The `EditSession` to retrieve coordinates from **/ - toScreenRange(session: EditSession): Range; + toScreenRange(session: IEditSession): Range; /** * Creates and returns a new `Range` based on the row and column of the given parameters. @@ -1837,6 +1996,7 @@ module AceAjax { * @param endColumn The ending column **/ declare var Range: { + fromPoints(pos1: Position, pos2: Position): Range; new(startRow: number, startColumn: number, endRow: number, endColumn: number): Range; } @@ -1844,7 +2004,7 @@ module AceAjax { /// RenderLoop //////////////// - interface RenderLoop { } + export interface RenderLoop { } declare var RenderLoop: { new(): RenderLoop; } @@ -1856,7 +2016,7 @@ module AceAjax { /** * A set of methods for setting and retrieving the editor's scrollbar. **/ - interface ScrollBar { + export interface ScrollBar { /** * Emitted when the scroll bar, well, scrolls. @@ -1902,7 +2062,7 @@ module AceAjax { /** * A class designed to handle all sorts of text searches within a [[Document `Document`]]. **/ - interface Search { + export interface Search { /** * Sets the search options via the `options` parameter. @@ -1925,13 +2085,13 @@ module AceAjax { * Searches for `options.needle`. If found, this method returns the [[Range `Range`]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session. * @param session The session to search with **/ - find(session: EditSession): Range; + find(session: IEditSession): Range; /** * Searches for all occurances `options.needle`. If found, this method returns an array of [[Range `Range`s]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session. * @param session The session to search with **/ - findAll(session: EditSession): Range[]; + findAll(session: IEditSession): Range[]; /** * Searches for `options.needle` in `input`, and, if found, replaces it with `replacement`. @@ -1966,10 +2126,24 @@ module AceAjax { * Contains the cursor position and the text selection of an edit session. * The row/columns used in the selection are in document coordinates representing ths coordinates as thez appear in the document before applying soft wrap and folding. **/ - interface Selection { + export interface Selection { + + addEventListener(ev: string, callback: Function); + + moveCursorWordLeft(); + + moveCursorWordRight(); + + fromOrientedRange(range: Range); + + setSelectionRange(match); + + getAllRanges(): Range[]; on(event: string, fn: (e) => any); + addRange(range: Range); + /** * Returns `true` if the selection is empty. **/ @@ -2187,7 +2361,7 @@ module AceAjax { * @param column The column to move to * @param keepDesiredColumn [If `true`, the cursor move does not respect the previous column]{: #preventUpdateBool} **/ - moveCursorTo(row: number, column: number, keepDesiredColumn: bool); + moveCursorTo(row: number, column: number, keepDesiredColumn?: bool); /** * Moves the cursor to the screen position indicated by row and column. {:preventUpdateBoolDesc} @@ -2202,14 +2376,14 @@ module AceAjax { * Creates a new `Selection` object. * @param session The session to use **/ - new(session: EditSession): Selection; + new(session: IEditSession): Selection; } //////////////// /// Split //////////////// - interface Split { + export interface Split { /** * Returns the number of splits. @@ -2267,7 +2441,7 @@ module AceAjax { * @param session The new edit session * @param idx The editor's index you're interested in **/ - setSession(session: EditSession, idx: number); + setSession(session: IEditSession, idx: number); /** * Returns the orientation. @@ -2296,7 +2470,7 @@ module AceAjax { /** * This class provides an essay way to treat the document as a stream of tokens, and provides methods to iterate over these tokens. **/ - interface TokenIterator { + export interface TokenIterator { /** * Tokenizes all the items from the current point to the row prior in the document. @@ -2311,7 +2485,7 @@ module AceAjax { /** * Returns the current tokenized string. **/ - getCurrentToken(): string; + getCurrentToken(): TokenInfo; /** * Returns the current row. @@ -2330,7 +2504,7 @@ module AceAjax { * @param initialRow The row to start the tokenizing at * @param initialColumn The column to start the tokenizing at **/ - new(session: EditSession, initialRow: number, initialColumn: number): TokenIterator; + new(session: IEditSession, initialRow: number, initialColumn: number): TokenIterator; } ////////////////// @@ -2341,7 +2515,7 @@ module AceAjax { /** * This class takes a set of highlighting rules, and creates a tokenizer out of them. For more information, see [the wiki on extending highlighters](https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#wiki-extendingTheHighlighter). **/ - interface Tokenizer { + export interface Tokenizer { /** * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state. @@ -2364,7 +2538,7 @@ module AceAjax { /** * This object maintains the undo stack for an [[EditSession `EditSession`]]. **/ - interface UndoManager { + export interface UndoManager { /** * Provides a means for implementing your own undo manager. `options` has one property, `args`, an [[Array `Array`]], with two elements: @@ -2416,12 +2590,20 @@ module AceAjax { /** * The class that is responsible for drawing everything you see on the screen! **/ - interface VirtualRenderer { + export interface VirtualRenderer { + + scroller: any; + + characterWidth: number; + + lineHeight: number; + + screenToTextCoordinates(left: number, top: number); /** * Associates the renderer with an [[EditSession `EditSession`]]. **/ - setSession(); + setSession(session: IEditSession); /** * Triggers a partial update of the text, from the range given by the two parameters. @@ -2748,7 +2930,7 @@ module AceAjax { * @param container The root element of the editor * @param theme The starting theme **/ - new(container: HTMLElement, theme: string): VirtualRenderer; + new(container: HTMLElement, theme?: string): VirtualRenderer; } } diff --git a/ace/all-tests.ts b/ace/all-tests.ts new file mode 100644 index 000000000..80717ac5d --- /dev/null +++ b/ace/all-tests.ts @@ -0,0 +1,26 @@ +/// + +var exports: any; +var assert: any; +var MockRenderer = null; +var JavaScriptMode = null; + +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// + + + diff --git a/ace/tests/ace-anchor-tests.ts b/ace/tests/ace-anchor-tests.ts new file mode 100644 index 000000000..40e81600a --- /dev/null +++ b/ace/tests/ace-anchor-tests.ts @@ -0,0 +1,131 @@ +/// + +exports = { + + "test create anchor" : function() { + var doc = new AceAjax.Document("juhu"); + var anchor = new AceAjax.Anchor(doc, 0, 0); + + assert.position(anchor.getPosition(), 0, 0); + assert.equal(anchor.getDocument(), doc); + }, + + "test insert text in same row before cursor should move anchor column": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 1, 4); + + doc.insert({row: 1, column: 1}, "123"); + assert.position(anchor.getPosition(), 1, 7); + }, + + "test insert lines before cursor should move anchor row": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 1, 4); + + doc.insertLines(1, ["123", "456"]); + assert.position(anchor.getPosition(), 3, 4); + }, + + "test insert new line before cursor should move anchor column": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 1, 4); + + doc.insertNewLine({row: 0, column: 0}); + assert.position(anchor.getPosition(), 2, 4); + }, + + "test insert new line in anchor line before anchor should move anchor column and row": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 1, 4); + + doc.insertNewLine({row: 1, column: 2}); + assert.position(anchor.getPosition(), 2, 2); + }, + + "test delete text in anchor line before anchor should move anchor column": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 1, 4); + + doc.remove(new AceAjax.Range(1, 1, 1, 3)); + assert.position(anchor.getPosition(), 1, 2); + }, + + "test remove range which contains the anchor should move the anchor to the start of the range": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 0, 3); + + doc.remove(new AceAjax.Range(0, 1, 1, 3)); + assert.position(anchor.getPosition(), 0, 1); + }, + + "test delete character before the anchor should have no effect": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 1, 4); + + doc.remove(new AceAjax.Range(1, 4, 1, 5)); + assert.position(anchor.getPosition(), 1, 4); + }, + + "test delete lines in anchor line before anchor should move anchor row": function() { + var doc = new AceAjax.Document("juhu\n1\n2\nkinners"); + var anchor = new AceAjax.Anchor(doc, 3, 4); + + doc.removeLines(1, 2); + assert.position(anchor.getPosition(), 1, 4); + }, + + "test remove new line before the cursor": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 1, 4); + + doc.removeNewLine(0); + assert.position(anchor.getPosition(), 0, 8); + }, + + "test delete range which contains the anchor should move anchor to the end of the range": function() { + var doc = new AceAjax.Document("juhu\nkinners"); + var anchor = new AceAjax.Anchor(doc, 1, 4); + + doc.remove(new AceAjax.Range(0, 2, 1, 2)); + assert.position(anchor.getPosition(), 0, 4); + }, + + "test delete line which contains the anchor should move anchor to the end of the range": function() { + var doc = new AceAjax.Document("juhu\nkinners\n123"); + var anchor = new AceAjax.Anchor(doc, 1, 5); + + doc.removeLines(1, 1); + assert.position(anchor.getPosition(), 1, 0); + }, + + "test remove after the anchor should have no effect": function() { + var doc = new AceAjax.Document("juhu\nkinners\n123"); + var anchor = new AceAjax.Anchor(doc, 1, 2); + + doc.remove(new AceAjax.Range(1, 4, 2, 2)); + assert.position(anchor.getPosition(), 1, 2); + }, + + "test anchor changes triggered by document changes should emit change event": function(next) { + var doc = new AceAjax.Document("juhu\nkinners\n123"); + var anchor = new AceAjax.Anchor(doc, 1, 5); + + anchor.on("change", function(e) { + assert.position(anchor.getPosition(), 0, 0); + next(); + }); + + doc.remove(new AceAjax.Range(0, 0, 2, 1)); + }, + + "test only fire change event if position changes": function() { + var doc = new AceAjax.Document("juhu\nkinners\n123"); + var anchor = new AceAjax.Anchor(doc, 1, 5); + + anchor.on("change", function(e) { + assert.fail(); + }); + + doc.remove(new AceAjax.Range(2, 0, 2, 1)); + } +}; diff --git a/ace/tests/ace-background_tokenizer-tests.ts b/ace/tests/ace-background_tokenizer-tests.ts new file mode 100644 index 000000000..8c29358a4 --- /dev/null +++ b/ace/tests/ace-background_tokenizer-tests.ts @@ -0,0 +1,39 @@ +/// + +function forceTokenize(session) { + for (var i = 0, l = session.getLength(); i < l; i++) + session.getTokens(i) +} + +function testStates(session, states) { + for (var i = 0, l = session.getLength(); i < l; i++) + assert.equal(session.bgTokenizer.states[i], states[i]) + assert.ok(l == states.length) +} + +exports = { + + "test background tokenizer update on session change": function() { + var doc = new AceAjax.EditSession([ + "/*", + "*/", + "var juhu" + ]); + doc.setMode("./mode/javascript") + + forceTokenize(doc) + testStates(doc, ["comment", "start", "start"]) + + doc.remove(new AceAjax.Range(0, 2, 1, 2)) + testStates(doc, [null, "start"]) + + forceTokenize(doc) + testStates(doc, ["comment", "comment"]) + + doc.insert({ row: 0, column: 2 }, "\n*/") + testStates(doc, [undefined, undefined, "comment"]) + + forceTokenize(doc) + testStates(doc, ["comment", "start", "start"]) + } +}; diff --git a/ace/ace-tests.ts b/ace/tests/ace-default-tests.ts similarity index 99% rename from ace/ace-tests.ts rename to ace/tests/ace-default-tests.ts index 43556fb83..dcd1ab103 100644 --- a/ace/ace-tests.ts +++ b/ace/tests/ace-default-tests.ts @@ -1,6 +1,4 @@ -/// - -var assert: any; +/// var editor = ace.edit("editor"); editor.setTheme("ace/theme/monokai"); @@ -450,4 +448,3 @@ editor.moveCursorTo(1, 0); editor.toLowerCase() assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n")); assert.position(editor.getCursorPosition(), 1, 0); - diff --git a/ace/tests/ace-document-tests.ts b/ace/tests/ace-document-tests.ts new file mode 100644 index 000000000..1f3e0a9a2 --- /dev/null +++ b/ace/tests/ace-document-tests.ts @@ -0,0 +1,254 @@ +/// + +exports = { + "test: insert text in line": function() { + var doc = new AceAjax.Document(["12", "34"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.insert({ row: 0, column: 1 }, "juhu"); + assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); + } , + + "test: insert new line": function() { + var doc = new AceAjax.Document(["12", "34"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.insertNewLine({ row: 0, column: 1 }); + assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); + } , + + "test: insert lines at the beginning": function() { + var doc = new AceAjax.Document(["12", "34"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.insertLines(0, ["aa", "bb"]); + assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); + } , + + "test: insert lines at the end": function() { + var doc = new AceAjax.Document(["12", "34"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.insertLines(2, ["aa", "bb"]); + assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n")); + } , + + "test: insert lines in the middle": function() { + var doc = new AceAjax.Document(["12", "34"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.insertLines(1, ["aa", "bb"]); + assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); + } , + + "test: insert multi line string at the start": function() { + var doc = new AceAjax.Document(["12", "34"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.insert({ row: 0, column: 0 }, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); + } , + + "test: insert multi line string at the end": function() { + var doc = new AceAjax.Document(["12", "34"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.insert({ row: 2, column: 0 }, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); + } , + + "test: insert multi line string in the middle": function() { + var doc = new AceAjax.Document(["12", "34"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.insert({ row: 0, column: 1 }, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); + } , + + "test: delete in line": function() { + var doc = new AceAjax.Document(["1234", "5678"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.remove(new AceAjax.Range(0, 1, 0, 3)); + assert.equal(doc.getValue(), ["14", "5678"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["14", "5678"].join("\n")); + } , + + "test: delete new line": function() { + var doc = new AceAjax.Document(["1234", "5678"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.remove(new AceAjax.Range(0, 4, 1, 0)); + assert.equal(doc.getValue(), ["12345678"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12345678"].join("\n")); + } , + + "test: delete multi line range line": function() { + var doc = new AceAjax.Document(["1234", "5678", "abcd"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.remove(new AceAjax.Range(0, 2, 2, 2)); + assert.equal(doc.getValue(), ["12cd"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678", "abcd"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12cd"].join("\n")); + } , + + "test: delete full lines": function() { + var doc = new AceAjax.Document(["1234", "5678", "abcd"]); + + var deltas = []; + doc.on("change", function (e) { deltas.push(e.data); }); + + doc.remove(new AceAjax.Range(1, 0, 3, 0)); + assert.equal(doc.getValue(), ["1234", ""].join("\n")); + } , + + "test: remove lines should return the removed lines": function() { + var doc = new AceAjax.Document(["1234", "5678", "abcd"]); + + var removed = doc.removeLines(1, 2); + assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n")); + } , + + "test: should handle unix style new lines": function() { + var doc = new AceAjax.Document(["1", "2", "3"]); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + } , + + "test: should handle windows style new lines": function() { + var doc = new AceAjax.Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("unix"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + } , + + "test: set new line mode to 'windows' should use '\\r\\n' as new lines": function() { + var doc = new AceAjax.Document(["1", "2", "3"].join("\n")); + doc.setNewLineMode("windows"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n")); + } , + + "test: set new line mode to 'unix' should use '\\n' as new lines": function() { + var doc = new AceAjax.Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("unix"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + } , + + "test: set new line mode to 'auto' should detect the incoming nl type": function() { + var doc = new AceAjax.Document(["1", "2", "3"].join("\n")); + + doc.setNewLineMode("auto"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + + var doc = new AceAjax.Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("auto"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n")); + + doc.replace(new AceAjax.Range(0, 0, 2, 1), ["4", "5", "6"].join("\n")); + assert.equal(["4", "5", "6"].join("\n"), doc.getValue()); + } , + + "test: set value": function() { + var doc = new AceAjax.Document("1"); + assert.equal("1", doc.getValue()); + + doc.setValue(doc.getValue()); + assert.equal("1", doc.getValue()); + + var doc = new AceAjax.Document("1\n2"); + assert.equal("1\n2", doc.getValue()); + + doc.setValue(doc.getValue()); + assert.equal("1\n2", doc.getValue()); + } +}; \ No newline at end of file diff --git a/ace/tests/ace-edit_session-tests.ts b/ace/tests/ace-edit_session-tests.ts new file mode 100644 index 000000000..12a3ce5bf --- /dev/null +++ b/ace/tests/ace-edit_session-tests.ts @@ -0,0 +1,919 @@ +/// + +var lang: any; + +function createFoldTestSession() { + var lines = [ + "function foo(items) {", + " for (var i=0; i>", [1, 2], 1); + } , + + "test get longest line": function() { + var session = new AceAjax.EditSession(["12"]); + session.setTabSize(4); + assert.equal(session.getScreenWidth(), 2); + + session.doc.insertNewLine({ row: 0, column: Infinity }); + session.doc.insertLines(1, ["123"]); + assert.equal(session.getScreenWidth(), 3); + + session.doc.insertNewLine({ row: 0, column: Infinity }); + session.doc.insertLines(1, ["\t\t"]); + + assert.equal(session.getScreenWidth(), 8); + + session.setTabSize(2); + assert.equal(session.getScreenWidth(), 4); + } , + + "test issue 83": function() { + var session = new AceAjax.EditSession(""); + var editor = new AceAjax.Editor(null, session); + var document = session.getDocument(); + + session.setUseWrapMode(true); + + document.insertLines(0, ["a", "b"]); + document.insertLines(2, ["c", "d"]); + document.removeLines(1, 2); + } , + + "test wrapMode init has to create wrapData array": function() { + var session = new AceAjax.EditSession("foo bar\nfoo bar"); + var editor = new AceAjax.Editor(null, session); + var document = session.getDocument(); + + session.setUseWrapMode(true); + session.setWrapLimitRange(3, 3); + session.adjustWrapLimit(80); + } , + + "test first line blank with wrap": function() { + var session = new AceAjax.EditSession("\nfoo"); + session.setUseWrapMode(true); + assert.equal(session.doc.getValue(), ["", "foo"].join("\n")); + } , + + "test first line blank with wrap 2": function() { + var session = new AceAjax.EditSession(""); + session.setUseWrapMode(true); + session.setValue("\nfoo"); + + assert.equal(session.doc.getValue(), ["", "foo"].join("\n")); + } , + + "test fold getFoldDisplayLine": function() { + var session = createFoldTestSession(); + function assertDisplayLine(foldLine, str) { + var line = session.getLine(foldLine.end.row); + var displayLine = + session.getFoldDisplayLine(foldLine, foldLine.end.row, line.length); + assert.equal(displayLine, str); + } + } , + + "test foldLine idxToPosition": function() { + var session = createFoldTestSession(); + + function assertIdx2Pos(foldLineIdx, idx, row, column) { + var foldLine = null; + assert.position(foldLine.idxToPosition(idx), row, column); + } + + // "function foo(items) {", + // " for (var i=0; i + +exports = { + + setUp: function(next) { + this.session1 = new AceAjax.EditSession(["abc", "def"]); + this.session2 = new AceAjax.EditSession(["ghi", "jkl"]); + + + var editor = new AceAjax.Editor(null); + next(); + } , + + "test: change document": function() { + var editor = new AceAjax.Editor(null); + + editor.setSession(this.session1); + assert.equal(editor.getSession(), this.session1); + + editor.setSession(this.session2); + assert.equal(editor.getSession(), this.session2); + } , + + "test: only changes to the new document should have effect": function () { + var editor = new AceAjax.Editor(null); + + var called = false; + editor.onDocumentChange = function () { + called = true; + }; + + editor.setSession(this.session1); + editor.setSession(this.session2); + + this.session1.duplicateLines(0, 0); + assert.notOk(called); + + this.session2.duplicateLines(0, 0); + assert.ok(called); + } , + + "test: should use cursor of new document": function () { + var editor = new AceAjax.Editor(null); + + this.session1.getSelection().moveCursorTo(0, 1); + this.session2.getSelection().moveCursorTo(1, 0); + + editor.setSession(this.session1); + assert.position(editor.getCursorPosition(), 0, 1); + + editor.setSession(this.session2); + assert.position(editor.getCursorPosition(), 1, 0); + } , + + "test: only changing the cursor of the new doc should not have an effect": function () { + var editor = new AceAjax.Editor(null); + + editor.onCursorChange = function () { + called = true; + }; + + editor.setSession(this.session1); + editor.setSession(this.session2); + assert.position(editor.getCursorPosition(), 0, 0); + + var called = false; + this.session1.getSelection().moveCursorTo(0, 1); + assert.position(editor.getCursorPosition(), 0, 0); + assert.notOk(called); + + this.session2.getSelection().moveCursorTo(1, 1); + assert.position(editor.getCursorPosition(), 1, 1); + assert.ok(called); + } , + + "test: should use selection of new document": function () { + var editor = new AceAjax.Editor(null); + + this.session1.getSelection().selectTo(0, 1); + this.session2.getSelection().selectTo(1, 0); + + editor.setSession(this.session1); + assert.position(editor.getSelection().getSelectionLead(), 0, 1); + + editor.setSession(this.session2); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); + } , + + "test: only changing the selection of the new doc should not have an effect": function () { + var editor = new AceAjax.Editor(null); + + editor.onSelectionChange = function () { + called = true; + }; + + editor.setSession(this.session1); + editor.setSession(this.session2); + assert.position(editor.getSelection().getSelectionLead(), 0, 0); + + var called = false; + this.session1.getSelection().selectTo(0, 1); + assert.position(editor.getSelection().getSelectionLead(), 0, 0); + assert.notOk(called); + + this.session2.getSelection().selectTo(1, 1); + assert.position(editor.getSelection().getSelectionLead(), 1, 1); + assert.ok(called); + } , + + "test: should use mode of new document": function () { + var editor = new AceAjax.Editor(null); + + editor.onChangeMode = function () { + called = true; + }; + editor.setSession(this.session1); + editor.setSession(this.session2); + + var called = false; + this.session1.setMode(new Text()); + assert.notOk(called); + + this.session2.setMode(null); + assert.ok(called); + } , + + "test: should use stop worker of old document": function (next) { + var editor = new AceAjax.Editor(null); + + var self = this; + + // 1. Open an editor and set the session to CssMode + self.editor.setSession(self.session1); + self.session1.setMode(null); + + // 2. Add a line or two of valid CSS. + self.session1.setValue("DIV { color: red; }"); + + // 3. Clear the session value. + self.session1.setValue(""); + + // 4. Set the session to HtmlMode + self.session1.setMode(null); + + // 5. Try to type valid HTML + self.session1.insert({ row: 0, column: 0 }, ""); + + setTimeout(function () { + assert.equal(Object.keys(self.session1.getAnnotations()).length, 0); + next(); + }, 600); + } +}; \ No newline at end of file diff --git a/ace/tests/ace-editor_highlight_selected_word-tests.ts b/ace/tests/ace-editor_highlight_selected_word-tests.ts new file mode 100644 index 000000000..7e06c8c50 --- /dev/null +++ b/ace/tests/ace-editor_highlight_selected_word-tests.ts @@ -0,0 +1,214 @@ +/// + +var lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + "Mauris at arcu mi, eu lobortis mauris. Quisque ut libero eget " + + "diam congue vehicula. Quisque ut odio ut mi aliquam tincidunt. " + + "Duis lacinia aliquam lorem eget eleifend. Morbi eget felis mi. " + + "Duis quam ligula, consequat vitae convallis volutpat, blandit " + + "nec neque. Nulla facilisi. Etiam suscipit lorem ac justo " + + "sollicitudin tristique. Phasellus ut posuere nunc. Aliquam " + + "scelerisque mollis felis non gravida. Vestibulum lacus sem, " + + "posuere non bibendum id, luctus non dolor. Aenean id metus " + + "lorem, vel dapibus est. Donec gravida feugiat augue nec " + + "accumsan.Lorem ipsum dolor sit amet, consectetur adipiscing " + + "elit. Nulla vulputate, velit vitae tincidunt congue, nunc " + + "augue accumsan velit, eu consequat turpis lectus ac orci. " + + "Pellentesque ornare dolor feugiat dui auctor eu varius nulla " + + "fermentum. Sed aliquam odio at velit lacinia vel fermentum " + + "felis sodales. In dignissim magna eget nunc lobortis non " + + "fringilla nibh ullamcorper. Donec facilisis malesuada elit " + + "at egestas. Etiam bibendum, diam vitae tempor aliquet, dui " + + "libero vehicula odio, eget bibendum mauris velit eu lorem.\n" + + "consectetur"; + +function callHighlighterUpdate(session: AceAjax.IEditSession, firstRow: number, lastRow: number) { + var rangeCount = 0; + var mockMarkerLayer = { drawSingleLineMarker: function () { rangeCount++; } } + return rangeCount; +} + +exports = { + setUp: function(next) { + var session = new AceAjax.EditSession(lipsum); + editor = new AceAjax.Editor(new MockRenderer(), session); + var selection = session.getSelection(); + next(); + } , + + "test: highlight selected words by default": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + assert.equal(editor.getHighlightSelectedWord(), true); + } , + + "test: highlight a word": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 9); + selection.selectWord(); + + var highlighter = null; + assert.ok(highlighter != null); + + var range = selection.getRange(); + assert.equal(session.getTextRange(range), "ipsum"); + assert.equal(highlighter.cache.length, 0); + assert.equal(callHighlighterUpdate(session, 0, 0), 2); + } , + + "test: highlight a word and clear highlight": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 8); + selection.selectWord(); + + var range = selection.getRange(); + assert.equal(session.getTextRange(range), "ipsum"); + assert.equal(callHighlighterUpdate(session, 0, 0), 2); + + session.highlight(""); + assert.equal(callHighlighterUpdate(session, 0, 0), 0); + } , + + "test: highlight another word": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + selection.moveCursorTo(0, 14); + selection.selectWord(); + + var range = selection.getRange(); + assert.equal(session.getTextRange(range), "dolor"); + assert.equal(callHighlighterUpdate(session, 0, 0), 4); + } , + + "test: no selection, no highlight": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + selection.clearSelection(); + assert.equal(callHighlighterUpdate(session, 0, 0), 0); + } , + + "test: select a word, no highlight": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + selection.moveCursorTo(0, 14); + selection.selectWord(); + + editor.setHighlightSelectedWord(false); + + var range = selection.getRange(); + assert.equal(session.getTextRange(range), "dolor"); + assert.equal(callHighlighterUpdate(session, 0, 0), 0); + } , + + "test: select a word with no matches": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.setHighlightSelectedWord(true); + + var currentOptions = this.search.getOptions(); + var newOptions = { + wrap: true, + wholeWord: true, + caseSensitive: true, + needle: "Mauris" + }; + this.search.set(newOptions); + + var match = this.search.find(session); + assert.notEqual(match, null, "found a match for 'Mauris'"); + + this.search.set(currentOptions); + + selection.setSelectionRange(match); + + assert.equal(session.getTextRange(match), "Mauris"); + assert.equal(callHighlighterUpdate(session, 0, 0), 1); + } , + + "test: partial word selection 1": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + selection.moveCursorTo(0, 14); + selection.selectWord(); + selection.selectLeft(); + + var range = selection.getRange(); + assert.equal(session.getTextRange(range), "dolo"); + assert.equal(callHighlighterUpdate(session, 0, 0), 0); + } , + + "test: partial word selection 2": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + selection.moveCursorTo(0, 13); + selection.selectWord(); + selection.selectRight(); + + var range = selection.getRange(); + assert.equal(session.getTextRange(range), "dolor "); + assert.equal(callHighlighterUpdate(session, 0, 0), 0); + } , + + "test: partial word selection 3": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + selection.moveCursorTo(0, 14); + selection.selectWord(); + selection.selectLeft(); + selection.shiftSelection(1); + + var range = selection.getRange(); + assert.equal(session.getTextRange(range), "olor"); + assert.equal(callHighlighterUpdate(session, 0, 0), 0); + } , + + "test: select last word": function () { + var selection = session.getSelection(); + var session = new AceAjax.EditSession(lipsum); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + selection.moveCursorTo(0, 1); + + var currentOptions = this.search.getOptions(); + var newOptions = { + wrap: true, + wholeWord: true, + caseSensitive: true, + backwards: true, + needle: "consectetur" + }; + this.search.set(newOptions); + + var match = this.search.find(session); + assert.notEqual(match, null, "found a match for 'consectetur'"); + assert.position(match.start, 1, 0); + + this.search.set(currentOptions); + + selection.setSelectionRange(match); + + assert.equal(session.getTextRange(match), "consectetur"); + assert.equal(callHighlighterUpdate(session, 0, 1), 3); + } +}; diff --git a/ace/tests/ace-editor_navigation-tests.ts b/ace/tests/ace-editor_navigation-tests.ts new file mode 100644 index 000000000..c97ee0cd2 --- /dev/null +++ b/ace/tests/ace-editor_navigation-tests.ts @@ -0,0 +1,117 @@ +/// + +exports = { + createEditSession: function (rows, cols) { + var line = new Array(cols + 1).join("a"); + var text = new Array(rows).join(line + "\n") + line; + return new AceAjax.EditSession(text); + }, + + "test: navigate to end of file should scroll the last line into view": function () { + var doc = this.createEditSession(200, 10); + var editor = new AceAjax.Editor(new MockRenderer(), doc); + + editor.navigateFileEnd(); + var cursor = editor.getCursorPosition(); + + assert.ok(editor.getFirstVisibleRow() <= cursor.row); + assert.ok(editor.getLastVisibleRow() >= cursor.row); + }, + + "test: navigate to start of file should scroll the first row into view": function () { + var doc = this.createEditSession(200, 10); + var editor = new AceAjax.Editor(new MockRenderer(), doc); + + editor.moveCursorTo(editor.getLastVisibleRow() + 20); + editor.navigateFileStart(); + + assert.equal(editor.getFirstVisibleRow(), 0); + }, + + "test: goto hidden line should scroll the line into the middle of the viewport": function () { + var editor = new AceAjax.Editor(new MockRenderer(), this.createEditSession(200, 5)); + + editor.navigateTo(0, 0); + editor.gotoLine(101); + assert.position(editor.getCursorPosition(), 100, 0); + assert.equal(editor.getFirstVisibleRow(), 89); + + editor.navigateTo(100, 0); + editor.gotoLine(11); + assert.position(editor.getCursorPosition(), 10, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(100, 0); + editor.gotoLine(6); + assert.position(editor.getCursorPosition(), 5, 0); + assert.equal(0, editor.getFirstVisibleRow(), 0); + + editor.navigateTo(100, 0); + editor.gotoLine(1); + assert.position(editor.getCursorPosition(), 0, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(0, 0); + editor.gotoLine(191); + assert.position(editor.getCursorPosition(), 190, 0); + assert.equal(editor.getFirstVisibleRow(), 179); + + editor.navigateTo(0, 0); + editor.gotoLine(196); + assert.position(editor.getCursorPosition(), 195, 0); + assert.equal(editor.getFirstVisibleRow(), 180); + }, + + "test: goto visible line should only move the cursor and not scroll": function () { + var editor = new AceAjax.Editor(new MockRenderer(), this.createEditSession(200, 5)); + + editor.navigateTo(0, 0); + editor.gotoLine(12); + assert.position(editor.getCursorPosition(), 11, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(30, 0); + editor.gotoLine(33); + assert.position(editor.getCursorPosition(), 32, 0); + assert.equal(editor.getFirstVisibleRow(), 30); + }, + + "test: navigate from the end of a long line down to a short line and back should maintain the curser column": function () { + var editor = new AceAjax.Editor(new MockRenderer(), new AceAjax.EditSession(["123456", "1"])); + + editor.navigateTo(0, 6); + assert.position(editor.getCursorPosition(), 0, 6); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 1); + + editor.navigateUp(); + assert.position(editor.getCursorPosition(), 0, 6); + }, + + "test: reset desired column on navigate left or right": function () { + var editor = new AceAjax.Editor(new MockRenderer(), new AceAjax.EditSession(["123456", "12"])); + + editor.navigateTo(0, 6); + assert.position(editor.getCursorPosition(), 0, 6); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 2); + + editor.navigateLeft(); + assert.position(editor.getCursorPosition(), 1, 1); + + editor.navigateUp(); + assert.position(editor.getCursorPosition(), 0, 1); + }, + + "test: typing text should update the desired column": function () { + var editor = new AceAjax.Editor(new MockRenderer(), new AceAjax.EditSession(["1234", "1234567890"])); + + editor.navigateTo(0, 3); + editor.insert("juhu"); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 7); + } +}; \ No newline at end of file diff --git a/ace/tests/ace-editor_text_edit-tests.ts b/ace/tests/ace-editor_text_edit-tests.ts new file mode 100644 index 000000000..9d618acc6 --- /dev/null +++ b/ace/tests/ace-editor_text_edit-tests.ts @@ -0,0 +1,498 @@ +/// + +exports = { + "test: delete line from the middle": function () { + var session = new AceAjax.EditSession(["a", "b", "c", "d"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.removeLines(); + + assert.equal(session.toString(), "a\nc\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + + editor.removeLines(); + + assert.equal(session.toString(), "a\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + + editor.removeLines(); + + assert.equal(session.toString(), "a"); + assert.position(editor.getCursorPosition(), 0, 1); + + editor.removeLines(); + + assert.equal(session.toString(), ""); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: delete multiple selected lines": function () { + var session = new AceAjax.EditSession(["a", "b", "c", "d"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.removeLines(); + assert.equal(session.toString(), "a\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + }, + + "test: delete first line": function () { + var session = new AceAjax.EditSession(["a", "b", "c"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.removeLines(); + + assert.equal(session.toString(), "b\nc"); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: delete last should also delete the new line of the previous line": function () { + var session = new AceAjax.EditSession(["a", "b", "c", ""].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(3, 0); + + editor.removeLines(); + assert.equal(session.toString(), "a\nb\nc"); + assert.position(editor.getCursorPosition(), 2, 1); + + editor.removeLines(); + assert.equal(session.toString(), "a\nb"); + assert.position(editor.getCursorPosition(), 1, 1); + }, + + "test: indent block": function () { + var session = new AceAjax.EditSession(["a12345", "b12345", "c12345"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 3); + editor.getSelection().selectDown(); + + editor.indent(); + + assert.equal(["a12345", " b12345", " c12345"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 2, 7); + + var range = editor.getSelectionRange(); + assert.position(range.start, 1, 7); + assert.position(range.end, 2, 7); + }, + + "test: indent selected lines": function () { + var session = new AceAjax.EditSession(["a12345", "b12345", "c12345"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 0); + editor.getSelection().selectDown(); + + editor.indent(); + assert.equal(["a12345", " b12345", "c12345"].join("\n"), session.toString()); + }, + + "test: no auto indent if cursor is before the {": function () { + var session = new AceAjax.EditSession("{", new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.onTextInput("\n"); + assert.equal(["", "{"].join("\n"), session.toString()); + }, + + "test: outdent block": function () { + var session = new AceAjax.EditSession([" a12345", " b12345", " c12345"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 5); + editor.getSelection().selectDown(); + editor.getSelection().selectDown(); + + editor.blockOutdent(); + assert.equal(session.toString(), [" a12345", "b12345", " c12345"].join("\n")); + + assert.position(editor.getCursorPosition(), 2, 1); + + var range = editor.getSelectionRange(); + assert.position(range.start, 0, 1); + assert.position(range.end, 2, 1); + + editor.blockOutdent(); + assert.equal(session.toString(), ["a12345", "b12345", "c12345"].join("\n")); + + var range = editor.getSelectionRange(); + assert.position(range.start, 0, 0); + assert.position(range.end, 2, 0); + }, + + "test: outent without a selection should update cursor": function () { + var session = new AceAjax.EditSession(" 12"); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 3); + editor.blockOutdent(" "); + + assert.equal(session.toString(), " 12"); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: comment lines should perserve selection": function () { + var session = new AceAjax.EditSession([" abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 2); + editor.getSelection().selectDown(); + editor.toggleCommentLines(); + + assert.equal(["// abc", "//cde"].join("\n"), session.toString()); + + var selection = editor.getSelectionRange(); + assert.position(selection.start, 0, 4); + assert.position(selection.end, 1, 4); + }, + + "test: uncomment lines should perserve selection": function () { + var session = new AceAjax.EditSession(["// abc", "//cde"].join("\n"), new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 1); + editor.getSelection().selectDown(); + editor.getSelection().selectRight(); + editor.getSelection().selectRight(); + + editor.toggleCommentLines(); + + assert.equal([" abc", "cde"].join("\n"), session.toString()); + assert.range(editor.getSelectionRange(), 0, 0, 1, 1); + }, + + "test: toggle comment lines twice should return the original text": function () { + var session = new AceAjax.EditSession([" abc", "cde", "fg"], new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.getSelection().selectDown(); + editor.getSelection().selectDown(); + + editor.toggleCommentLines(); + editor.toggleCommentLines(); + + assert.equal([" abc", "cde", "fg"].join("\n"), session.toString()); + }, + + + "test: comment lines - if the selection end is at the line start it should stay there": function () { + //select down + var session = new AceAjax.EditSession(["abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.getSelection().selectDown(); + + editor.toggleCommentLines(); + assert.range(editor.getSelectionRange(), 0, 2, 1, 0); + + // select up + var session = new AceAjax.EditSession(["abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 0); + editor.getSelection().selectUp(); + + editor.toggleCommentLines(); + assert.range(editor.getSelectionRange(), 0, 2, 1, 0); + }, + + "test: move lines down should select moved lines": function () { + var session = new AceAjax.EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 1); + editor.getSelection().selectDown(); + + editor.moveLinesDown(); + assert.equal(["33", "11", "22", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); + + editor.moveLinesDown(); + assert.equal(["33", "44", "11", "22"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 2, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 2); + assert.position(editor.getSelection().getSelectionLead(), 2, 0); + + // moving again should have no effect + editor.moveLinesDown(); + assert.equal(["33", "44", "11", "22"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 2, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 2); + assert.position(editor.getSelection().getSelectionLead(), 2, 0); + }, + + "test: move lines up should select moved lines": function () { + var session = new AceAjax.EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(2, 1); + editor.getSelection().selectDown(); + + editor.moveLinesUp(); + assert.equal(session.toString(), ["11", "33", "44", "22"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); + + editor.moveLinesUp(); + assert.equal(session.toString(), ["33", "44", "11", "22"].join("\n")); + assert.position(editor.getCursorPosition(), 0, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 2, 0); + assert.position(editor.getSelection().getSelectionLead(), 0, 0); + }, + + "test: move line without active selection should not move cursor relative to the moved line": function () { + var session = new AceAjax.EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.clearSelection(); + + editor.moveLinesDown(); + assert.equal(["11", "33", "22", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 2, 1); + + editor.clearSelection(); + + editor.moveLinesUp(); + assert.equal(["11", "22", "33", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 1, 1); + }, + + "test: copy lines down should select lines and place cursor at the selection start": function () { + var session = new AceAjax.EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.copyLinesDown(); + assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 3, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 5, 0); + assert.position(editor.getSelection().getSelectionLead(), 3, 0); + }, + + "test: copy lines up should select lines and place cursor at the selection start": function () { + var session = new AceAjax.EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.copyLinesUp(); + assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); + }, + + "test: input a tab with soft tab should convert it to spaces": function () { + var session = new AceAjax.EditSession(""); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + session.setTabSize(2); + session.setUseSoftTabs(true); + + editor.onTextInput("\t"); + assert.equal(session.toString(), " "); + + session.setTabSize(5); + editor.onTextInput("\t"); + assert.equal(session.toString(), " "); + }, + + "test: input tab without soft tabs should keep the tab character": function () { + var session = new AceAjax.EditSession(""); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + session.setUseSoftTabs(false); + + editor.onTextInput("\t"); + assert.equal(session.toString(), "\t"); + }, + + "test: undo/redo for delete line": function () { + var session = new AceAjax.EditSession(["111", "222", "333"]); + var undoManager = new AceAjax.UndoManager(); + session.setUndoManager(undoManager); + + var initialText = session.toString(); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + editor.removeLines(); + var step1 = session.toString(); + assert.equal(step1, "222\n333"); + + editor.removeLines(); + var step2 = session.toString(); + assert.equal(step2, "333"); + + editor.removeLines(); + var step3 = session.toString(); + assert.equal(step3, ""); + + undoManager.undo(); + assert.equal(session.toString(), step2); + + undoManager.undo(); + assert.equal(session.toString(), step1); + + undoManager.undo(); + assert.equal(session.toString(), initialText); + + undoManager.undo(); + assert.equal(session.toString(), initialText); + }, + + "test: remove left should remove character left of the cursor": function () { + var session = new AceAjax.EditSession(["123", "456"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 1); + editor.remove("left"); + assert.equal(session.toString(), "123\n56"); + }, + + "test: remove left should remove line break if cursor is at line start": function () { + var session = new AceAjax.EditSession(["123", "456"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.remove("left"); + assert.equal(session.toString(), "123456"); + }, + + "test: remove left should remove tabsize spaces if cursor is on a tab stop and preceeded by spaces": function () { + var session = new AceAjax.EditSession(["123", " 456"]); + session.setUseSoftTabs(true); + session.setTabSize(4); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 8); + editor.remove("left"); + assert.equal(session.toString(), "123\n 456"); + }, + + "test: transpose at line start should be a noop": function () { + var session = new AceAjax.EditSession(["123", "4567", "89"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4567", "89"].join("\n")); + }, + + "test: transpose in line should swap the charaters before and after the cursor": function () { + var session = new AceAjax.EditSession(["123", "4567", "89"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4657", "89"].join("\n")); + }, + + "test: transpose at line end should swap the last two characters": function () { + var session = new AceAjax.EditSession(["123", "4567", "89"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 4); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4576", "89"].join("\n")); + }, + + "test: transpose with non empty selection should be a noop": function () { + var session = new AceAjax.EditSession(["123", "4567", "89"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 1); + editor.getSelection().selectRight(); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4567", "89"].join("\n")); + }, + + "test: transpose should move the cursor behind the last swapped character": function () { + var session = new AceAjax.EditSession(["123", "4567", "89"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.transposeLetters(); + assert.position(editor.getCursorPosition(), 1, 3); + }, + + "test: remove to line end": function () { + var session = new AceAjax.EditSession(["123", "4567", "89"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.removeToLineEnd(); + assert.equal(session.getValue(), ["123", "45", "89"].join("\n")); + }, + + "test: remove to line end at line end should remove the new line": function () { + var session = new AceAjax.EditSession(["123", "4567", "89"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 4); + editor.removeToLineEnd(); + assert.position(editor.getCursorPosition(), 1, 4); + assert.equal(session.getValue(), ["123", "456789"].join("\n")); + }, + + "test: transform selection to uppercase": function () { + var session = new AceAjax.EditSession(["ajax", "dot", "org"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.getSelection().selectLineEnd(); + editor.toUpperCase() + assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n")); + }, + + "test: transform word to uppercase": function () { + var session = new AceAjax.EditSession(["ajax", "dot", "org"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.toUpperCase() + assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + }, + + "test: transform selection to lowercase": function () { + var session = new AceAjax.EditSession(["AJAX", "DOT", "ORG"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.getSelection().selectLineEnd(); + editor.toLowerCase() + assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n")); + }, + + "test: transform word to lowercase": function () { + var session = new AceAjax.EditSession(["AJAX", "DOT", "ORG"]); + + var editor = new AceAjax.Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.toLowerCase() + assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + } +}; \ No newline at end of file diff --git a/ace/tests/ace-multi_select-tests.ts b/ace/tests/ace-multi_select-tests.ts new file mode 100644 index 000000000..ade1493e2 --- /dev/null +++ b/ace/tests/ace-multi_select-tests.ts @@ -0,0 +1,111 @@ +/// + +var exec = function (name?, times?, args?) { + do { + editor.commands.exec(name, editor, args); + } while (times-- > 1) +}; +var testRanges = function (str) { + assert.equal(editor.selection.getAllRanges() + "", str + ""); +} + +exports = { + + name: "ACE multi_select.js", + + "test: multiselect editing": function() { + var doc = new AceAjax.EditSession([ + "w1.w2", + " wtt.w", + " wtt.w" + ]); + editor = new AceAjax.Editor(new MockRenderer(), doc); + + editor.navigateFileEnd(); + exec("selectMoreBefore", 3); + assert.ok(editor.inMultiSelectMode); + assert.equal(editor.selection.getAllRanges().length, 4); + + var newLine = editor.session.getDocument().getNewLineCharacter(); + var copyText = "wwww".split("").join(newLine); + assert.equal(editor.getCopyText(), copyText); + exec("insertstring", 1, "a"); + exec("backspace", 2); + assert.equal(editor.session.getValue(), "w1.w2\ntt\ntt"); + assert.equal(editor.selection.getAllRanges().length, 4); + + exec("selectall"); + assert.ok(!editor.inMultiSelectMode); + //assert.equal(editor.selection.getAllRanges().length, 1); + } , + + "test: multiselect navigation": function() { + var doc = new AceAjax.EditSession([ + "w1.w2", + " wtt.w", + " wtt.we" + ]); + editor = new AceAjax.Editor(new MockRenderer(), doc); + + editor.selectMoreLines(1); + testRanges("Range: [0/0] -> [0/0],Range: [1/0] -> [1/0]"); + assert.ok(editor.inMultiSelectMode); + + exec("golinedown"); + exec("gotolineend"); + testRanges("Range: [1/9] -> [1/9],Range: [2/10] -> [2/10]"); + exec("selectwordleft"); + + testRanges("Range: [1/8] -> [1/9],Range: [2/8] -> [2/10]"); + exec("golinedown", 2); + assert.ok(!editor.inMultiSelectMode); + } , + + "test: multiselect session change": function() { + var doc = new AceAjax.EditSession([ + "w1.w2", + " wtt.w", + " wtt.w" + ]); + editor = new AceAjax.Editor(new MockRenderer(), doc); + + editor.selectMoreLines(1) + testRanges("Range: [0/0] -> [0/0],Range: [1/0] -> [1/0]"); + assert.ok(editor.inMultiSelectMode); + + var doc2 = new AceAjax.EditSession(["w1"]); + editor.setSession(doc2); + assert.ok(!editor.inMultiSelectMode); + + editor.setSession(doc); + assert.ok(editor.inMultiSelectMode); + } , + + "test: multiselect addRange": function() { + var doc = new AceAjax.EditSession([ + "w1.w2", + " wtt.w", + " wtt.w" + ]); + editor = new AceAjax.Editor(new MockRenderer(), doc); + + var selection = editor.selection; + + var range1 = new AceAjax.Range(0, 2, 0, 4); + editor.selection.fromOrientedRange(range1); + + var range2 = new AceAjax.Range(0, 3, 0, 4); + selection.addRange(range2); + assert.ok(!editor.inMultiSelectMode); + assert.ok(range2.isEqual(editor.selection.getRange())); + + var range3 = new AceAjax.Range(0, 1, 0, 1); + selection.addRange(range3); + assert.ok(editor.inMultiSelectMode); + testRanges([range3, range2]); + + var range4 = new AceAjax.Range(0, 0, 4, 0); + selection.addRange(range4); + assert.ok(!editor.inMultiSelectMode); + } +}; diff --git a/ace/tests/ace-placeholder-tests.ts b/ace/tests/ace-placeholder-tests.ts new file mode 100644 index 000000000..124554cf7 --- /dev/null +++ b/ace/tests/ace-placeholder-tests.ts @@ -0,0 +1,106 @@ +/// + +exports = { + + "test: simple at the end appending of text": function () { + var session = new AceAjax.EditSession("var a = 10;\nconsole.log(a, a);", new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + new AceAjax.PlaceHolder(session, 1, { row: 0, column: 4 }, [{ row: 1, column: 12 }, { row: 1, column: 15 }]); + + editor.moveCursorTo(0, 5); + editor.insert('b'); + assert.equal(session.doc.getValue(), "var ab = 10;\nconsole.log(ab, ab);"); + editor.insert('cd'); + assert.equal(session.doc.getValue(), "var abcd = 10;\nconsole.log(abcd, abcd);"); + editor.remove('left'); + editor.remove('left'); + editor.remove('left'); + assert.equal(session.doc.getValue(), "var a = 10;\nconsole.log(a, a);"); + }, + + "test: inserting text outside placeholder": function () { + var session = new AceAjax.EditSession("var a = 10;\nconsole.log(a, a);\n", new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + new AceAjax.PlaceHolder(session, 1, { row: 0, column: 4 }, [{ row: 1, column: 12 }, { row: 1, column: 15 }]); + + editor.moveCursorTo(2, 0); + editor.insert('b'); + assert.equal(session.doc.getValue(), "var a = 10;\nconsole.log(a, a);\nb"); + }, + + "test: insertion at the beginning": function (next) { + var session = new AceAjax.EditSession("var a = 10;\nconsole.log(a, a);", new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + var p = new AceAjax.PlaceHolder(session, 1, { row: 0, column: 4 }, [{ row: 1, column: 12 }, { row: 1, column: 15 }]); + + editor.moveCursorTo(0, 4); + editor.insert('$'); + assert.equal(session.doc.getValue(), "var $a = 10;\nconsole.log($a, $a);"); + editor.moveCursorTo(0, 4); + // Have to put this in a setTimeout because the anchor is only fixed later. + setTimeout(function () { + editor.insert('v'); + assert.equal(session.doc.getValue(), "var v$a = 10;\nconsole.log(v$a, v$a);"); + next(); + }, 10); + }, + + "test: detaching placeholder": function () { + var session = new AceAjax.EditSession("var a = 10;\nconsole.log(a, a);", new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + var p = new AceAjax.PlaceHolder(session, 1, { row: 0, column: 4 }, [{ row: 1, column: 12 }, { row: 1, column: 15 }]); + + editor.moveCursorTo(0, 5); + editor.insert('b'); + assert.equal(session.doc.getValue(), "var ab = 10;\nconsole.log(ab, ab);"); + p.detach(); + editor.insert('cd'); + assert.equal(session.doc.getValue(), "var abcd = 10;\nconsole.log(ab, ab);"); + }, + + "test: events": function () { + var session = new AceAjax.EditSession("var a = 10;\nconsole.log(a, a);", new JavaScriptMode()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + + var p = new AceAjax.PlaceHolder(session, 1, { row: 0, column: 4 }, [{ row: 1, column: 12 }, { row: 1, column: 15 }]); + var entered = false; + var left = false; + p.on("cursorEnter", function () { + entered = true; + }); + p.on("cursorLeave", function () { + left = true; + }); + + editor.moveCursorTo(0, 0); + editor.moveCursorTo(0, 4); + p.onCursorChange(); // Have to do this by hand because moveCursorTo doesn't trigger the event + assert.ok(entered); + editor.moveCursorTo(1, 0); + p.onCursorChange(); // Have to do this by hand because moveCursorTo doesn't trigger the event + assert.ok(left); + }, + + "test: cancel": function (next) { + var session = new AceAjax.EditSession("var a = 10;\nconsole.log(a, a);", new JavaScriptMode()); + session.setUndoManager(new AceAjax.UndoManager()); + var editor = new AceAjax.Editor(new MockRenderer(), session); + var p = new AceAjax.PlaceHolder(session, 1, { row: 0, column: 4 }, [{ row: 1, column: 12 }, { row: 1, column: 15 }]); + + editor.moveCursorTo(0, 5); + editor.insert('b'); + editor.insert('cd'); + editor.remove('left'); + assert.equal(session.doc.getValue(), "var abc = 10;\nconsole.log(abc, abc);"); + // Wait a little for the changes to enter the undo stack + setTimeout(function () { + p.cancel(); + assert.equal(session.doc.getValue(), "var a = 10;\nconsole.log(a, a);"); + next(); + }, 80); + } +}; diff --git a/ace/tests/ace-range-tests.ts b/ace/tests/ace-range-tests.ts new file mode 100644 index 000000000..8a1b1ccc6 --- /dev/null +++ b/ace/tests/ace-range-tests.ts @@ -0,0 +1,146 @@ +/// + +exports = { + + name: "ACE range.js", + + "test: create range": function () { + var range = new AceAjax.Range(1, 2, 3, 4); + + assert.equal(range.start.row, 1); + assert.equal(range.start.column, 2); + assert.equal(range.end.row, 3); + assert.equal(range.end.column, 4); + }, + + "test: create from points": function () { + var range = AceAjax.Range.fromPoints({ row: 1, column: 2 }, { row: 3, column: 4 }); + + assert.equal(range.start.row, 1); + assert.equal(range.start.column, 2); + assert.equal(range.end.row, 3); + assert.equal(range.end.column, 4); + }, + + "test: clip to rows": function () { + assert.range(new AceAjax.Range(0, 20, 100, 30).clipRows(10, 30), 10, 0, 31, 0); + assert.range(new AceAjax.Range(0, 20, 30, 10).clipRows(10, 30), 10, 0, 30, 10); + + var range = new AceAjax.Range(0, 20, 3, 10); + var range = range.clipRows(10, 30); + + assert.ok(range.isEmpty()); + assert.range(range, 10, 0, 10, 0); + }, + + "test: isEmpty": function () { + var range = new AceAjax.Range(1, 2, 1, 2); + assert.ok(range.isEmpty()); + + var range = new AceAjax.Range(1, 2, 1, 6); + assert.notOk(range.isEmpty()); + }, + + "test: is multi line": function () { + var range = new AceAjax.Range(1, 2, 1, 6); + assert.notOk(range.isMultiLine()); + + var range = new AceAjax.Range(1, 2, 2, 6); + assert.ok(range.isMultiLine()); + }, + + "test: clone": function () { + var range = new AceAjax.Range(1, 2, 3, 4); + var clone = range.clone(); + + assert.position(clone.start, 1, 2); + assert.position(clone.end, 3, 4); + + clone.start.column = 20; + assert.position(range.start, 1, 2); + + clone.end.column = 20; + assert.position(range.end, 3, 4); + }, + + "test: contains for multi line ranges": function () { + var range = new AceAjax.Range(1, 10, 5, 20); + + assert.ok(range.contains(1, 10)); + assert.ok(range.contains(2, 0)); + assert.ok(range.contains(3, 100)); + assert.ok(range.contains(5, 19)); + assert.ok(range.contains(5, 20)); + + assert.notOk(range.contains(1, 9)); + assert.notOk(range.contains(0, 0)); + assert.notOk(range.contains(5, 21)); + }, + + "test: contains for single line ranges": function () { + var range = new AceAjax.Range(1, 10, 1, 20); + + assert.ok(range.contains(1, 10)); + assert.ok(range.contains(1, 15)); + assert.ok(range.contains(1, 20)); + + assert.notOk(range.contains(0, 9)); + assert.notOk(range.contains(2, 9)); + assert.notOk(range.contains(1, 9)); + assert.notOk(range.contains(1, 21)); + }, + + "test: extend range": function () { + var range = new AceAjax.Range(2, 10, 2, 30); + + var range = range.extend(2, 5); + assert.range(range, 2, 5, 2, 30); + + var range = range.extend(2, 35); + assert.range(range, 2, 5, 2, 35); + + var range = range.extend(2, 15); + assert.range(range, 2, 5, 2, 35); + + var range = range.extend(1, 4); + assert.range(range, 1, 4, 2, 35); + + var range = range.extend(6, 10); + assert.range(range, 1, 4, 6, 10); + }, + + "test: collapse rows": function () { + var range = new AceAjax.Range(0, 2, 1, 2); + assert.range(range.collapseRows(), 0, 0, 1, 0); + + var range = new AceAjax.Range(2, 2, 3, 1); + assert.range(range.collapseRows(), 2, 0, 3, 0); + + var range = new AceAjax.Range(2, 2, 3, 0); + assert.range(range.collapseRows(), 2, 0, 2, 0); + + var range = new AceAjax.Range(2, 0, 2, 0); + assert.range(range.collapseRows(), 2, 0, 2, 0); + }, + + "test: to screen range": function () { + var session = new AceAjax.EditSession([ + "juhu", + "12\t\t34", + "ぁぁa", + "\t\t34", + ]); + + var range = new AceAjax.Range(0, 0, 0, 3); + assert.range(range.toScreenRange(session), 0, 0, 0, 3); + + var range = new AceAjax.Range(1, 1, 1, 3); + assert.range(range.toScreenRange(session), 1, 1, 1, 4); + + var range = new AceAjax.Range(2, 1, 2, 2); + assert.range(range.toScreenRange(session), 2, 2, 2, 4); + + var range = new AceAjax.Range(3, 0, 3, 4); + assert.range(range.toScreenRange(session), 3, 0, 3, 10); + } +}; diff --git a/ace/tests/ace-range_list-tests.ts b/ace/tests/ace-range_list-tests.ts new file mode 100644 index 000000000..83f3c8a91 --- /dev/null +++ b/ace/tests/ace-range_list-tests.ts @@ -0,0 +1,117 @@ +/// + +function flatten(rangeList) { + var points = []; + rangeList.ranges.forEach(function (r) { + points.push(r.start.row, r.start.column, r.end.row, r.end.column) + }) + return points; +} +function testRangeList(rangeList, points) { + assert.equal("" + flatten(rangeList), "" + points); +} + +exports = { + + name: "ACE range_list.js", + + "test: rangeList pointIndex": function() { + var rangeList = new AceAjax.RangeList(); + rangeList.ranges = [ + new AceAjax.Range(1, 2, 3, 4), + new AceAjax.Range(4, 2, 5, 4), + new AceAjax.Range(8, 8, 9, 9) + ]; + + assert.equal(rangeList.pointIndex({ row: 0, column: 1 }), -1); + assert.equal(rangeList.pointIndex({ row: 1, column: 2 }), 0); + assert.equal(rangeList.pointIndex({ row: 1, column: 3 }), 0); + assert.equal(rangeList.pointIndex({ row: 3, column: 4 }), 0); + assert.equal(rangeList.pointIndex({ row: 4, column: 1 }), -2); + assert.equal(rangeList.pointIndex({ row: 5, column: 1 }), 1); + assert.equal(rangeList.pointIndex({ row: 8, column: 9 }), 2); + assert.equal(rangeList.pointIndex({ row: 18, column: 9 }), -4); + } , + + "test: rangeList add": function() { + var rangeList = new AceAjax.RangeList(); + rangeList.addList([ + new AceAjax.Range(9, 0, 9, 1), + new AceAjax.Range(1, 2, 3, 4), + new AceAjax.Range(8, 8, 9, 9), + new AceAjax.Range(4, 2, 5, 4), + new AceAjax.Range(3, 20, 3, 24), + new AceAjax.Range(6, 6, 7, 7) + ]); + assert.equal(rangeList.ranges.length, 5); + + rangeList.add(new AceAjax.Range(1, 2, 3, 5)); + assert.range(rangeList.ranges[0], 1, 2, 3, 5); + assert.equal(rangeList.ranges.length, 5); + + rangeList.add(new AceAjax.Range(7, 7, 7, 7)); + assert.range(rangeList.ranges[3], 7, 7, 7, 7); + rangeList.add(new AceAjax.Range(7, 8, 7, 8)); + assert.range(rangeList.ranges[4], 7, 8, 7, 8); + } , + + "test: rangeList add empty": function() { + var rangeList = new AceAjax.RangeList(); + rangeList.addList([ + new AceAjax.Range(7, 10, 7, 10), + new AceAjax.Range(9, 10, 9, 10), + new AceAjax.Range(8, 10, 8, 10) + ]); + assert.equal(rangeList.ranges.length, 3); + + rangeList.add(new AceAjax.Range(9, 10, 9, 10)); + testRangeList(rangeList, [7, 10, 7, 10, 8, 10, 8, 10, 9, 10, 9, 10]); + } , + + "test: rangeList merge": function() { + var rangeList = new AceAjax.RangeList(); + rangeList.addList([ + new AceAjax.Range(1, 2, 3, 4), + new AceAjax.Range(4, 2, 5, 4), + new AceAjax.Range(6, 6, 7, 7), + new AceAjax.Range(8, 8, 9, 9) + ]); + var removed = []; + + assert.equal(rangeList.ranges.length, 4); + + rangeList.ranges[1].end.row = 7; + removed = rangeList.merge(); + assert.equal(removed.length, 1); + assert.range(rangeList.ranges[1], 4, 2, 7, 7); + assert.equal(rangeList.ranges.length, 3); + + rangeList.ranges[0].end.row = 10; + removed = rangeList.merge(); + assert.range(rangeList.ranges[0], 1, 2, 10, 4); + assert.equal(removed.length, 2); + assert.equal(rangeList.ranges.length, 1); + + rangeList.ranges.push(new AceAjax.Range(10, 10, 10, 10)); + rangeList.ranges.push(new AceAjax.Range(10, 10, 10, 10)); + removed = rangeList.merge(); + assert.equal(rangeList.ranges.length, 2); + } , + + "test: rangeList remove": function() { + var rangeList = new AceAjax.RangeList(); + var list = [ + new AceAjax.Range(1, 2, 3, 4), + new AceAjax.Range(4, 2, 5, 4), + new AceAjax.Range(6, 6, 7, 7), + new AceAjax.Range(8, 8, 9, 9) + ]; + rangeList.addList(list); + assert.equal(rangeList.ranges.length, 4); + rangeList.substractPoint({ row: 1, column: 2 }); + assert.equal(rangeList.ranges.length, 3); + rangeList.substractPoint({ row: 6, column: 7 }); + assert.equal(rangeList.ranges.length, 2); + } + +}; diff --git a/ace/tests/ace-search-tests.ts b/ace/tests/ace-search-tests.ts new file mode 100644 index 000000000..c30139d65 --- /dev/null +++ b/ace/tests/ace-search-tests.ts @@ -0,0 +1,416 @@ +/// + +exports = { + "test: configure the search object": function () { + var search = new AceAjax.Search(); + search.set({ + needle: "juhu" + }); + }, + + "test: find simple text in document": function () { + var session = new AceAjax.EditSession(["juhu kinners 123", "456"]); + var search = new AceAjax.Search().set({ + needle: "kinners" + }); + + var range = search.find(session); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 12); + }, + + "test: find simple text in next line": function () { + var session = new AceAjax.EditSession(["abc", "juhu kinners 123", "456"]); + var search = new AceAjax.Search().set({ + needle: "kinners" + }); + + var range = search.find(session); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); + }, + + "test: find text starting at cursor position": function () { + var session = new AceAjax.EditSession(["juhu kinners", "juhu kinners 123"]); + session.getSelection().moveCursorTo(0, 6); + var search = new AceAjax.Search().set({ + needle: "kinners" + }); + + var range = search.find(session); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); + }, + + "test: wrap search is on by default": function () { + var session = new AceAjax.EditSession(["abc", "juhu kinners 123", "456"]); + session.getSelection().moveCursorTo(2, 1); + + var search = new AceAjax.Search().set({ + needle: "kinners" + }); + + assert.notEqual(search.find(session), null); + }, + + "test: wrap search should wrap at file end": function () { + var session = new AceAjax.EditSession(["abc", "juhu kinners 123", "456"]); + session.getSelection().moveCursorTo(2, 1); + + var search = new AceAjax.Search().set({ + needle: "kinners", + wrap: true + }); + + var range = search.find(session); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); + }, + + "test: wrap search should find needle even if it starts inside it": function () { + var session = new AceAjax.EditSession(["abc", "juhu kinners 123", "456"]); + session.getSelection().moveCursorTo(6, 1); + + var search = new AceAjax.Search().set({ + needle: "kinners", + wrap: true + }); + + var range = search.find(session); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); + }, + + "test: wrap search with no match should return 'null'": function () { + var session = new AceAjax.EditSession(["abc", "juhu kinners 123", "456"]); + session.getSelection().moveCursorTo(2, 1); + + var search = new AceAjax.Search().set({ + needle: "xyz", + wrap: true + }); + + assert.equal(search.find(session), null); + }, + + "test: case sensitive is by default off": function () { + var session = new AceAjax.EditSession(["abc", "juhu kinners 123", "456"]); + + var search = new AceAjax.Search().set({ + needle: "JUHU" + }); + + assert.range(search.find(session), 1, 0, 1, 4); + }, + + "test: case sensitive search": function () { + var session = new AceAjax.EditSession(["abc", "juhu kinners 123", "456"]); + + var search = new AceAjax.Search().set({ + needle: "KINNERS", + caseSensitive: true + }); + + var range = search.find(session); + assert.equal(range, null); + }, + + "test: whole word search should not match inside of words": function () { + var session = new AceAjax.EditSession(["juhukinners", "juhu kinners 123", "456"]); + + var search = new AceAjax.Search().set({ + needle: "kinners", + wholeWord: true + }); + + var range = search.find(session); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); + }, + + "test: find backwards": function () { + var session = new AceAjax.EditSession(["juhu juhu juhu juhu"]); + session.getSelection().moveCursorTo(0, 10); + var search = new AceAjax.Search().set({ + needle: "juhu", + backwards: true + }); + + var range = search.find(session); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 9); + }, + + "test: find in selection": function () { + var session = new AceAjax.EditSession(["juhu", "juhu", "juhu", "juhu"]); + session.getSelection().setSelectionAnchor(1, 0); + session.getSelection().selectTo(3, 5); + + var search = new AceAjax.Search().set({ + needle: "juhu", + wrap: true, + range: session.getSelection().getRange() + }); + + var range = search.find(session); + assert.position(range.start, 1, 0); + assert.position(range.end, 1, 4); + + search = new AceAjax.Search().set({ + needle: "juhu", + wrap: true, + range: session.getSelection().getRange() + }); + + session.getSelection().setSelectionAnchor(0, 2); + session.getSelection().selectTo(3, 2); + + var range = search.find(session); + assert.position(range.start, 1, 0); + assert.position(range.end, 1, 4); + }, + + "test: find backwards in selection": function () { + var session = new AceAjax.EditSession(["juhu", "juhu", "juhu", "juhu"]); + + session.getSelection().setSelectionAnchor(0, 2); + session.getSelection().selectTo(3, 2); + + var search = new AceAjax.Search().set({ + needle: "juhu", + wrap: true, + backwards: true, + range: session.getSelection().getRange() + }); + + var range = search.find(session); + assert.position(range.start, 2, 0); + assert.position(range.end, 2, 4); + + search = new AceAjax.Search().set({ + needle: "juhu", + wrap: true, + range: session.getSelection().getRange() + }); + + session.getSelection().setSelectionAnchor(0, 2); + session.getSelection().selectTo(1, 2); + + var range = search.find(session); + assert.position(range.start, 1, 0); + assert.position(range.end, 1, 4); + }, + + "test: edge case - match directly before the cursor": function () { + var session = new AceAjax.EditSession(["123", "123", "juhu"]); + + var search = new AceAjax.Search().set({ + needle: "juhu", + wrap: true + }); + + session.getSelection().moveCursorTo(2, 5); + + var range = search.find(session); + assert.position(range.start, 2, 0); + assert.position(range.end, 2, 4); + }, + + "test: edge case - match backwards directly after the cursor": function () { + var session = new AceAjax.EditSession(["123", "123", "juhu"]); + + var search = new AceAjax.Search().set({ + needle: "juhu", + wrap: true, + backwards: true + }); + + session.getSelection().moveCursorTo(2, 0); + + var range = search.find(session); + assert.position(range.start, 2, 0); + assert.position(range.end, 2, 4); + }, + + "test: find using a regular expression": function () { + var session = new AceAjax.EditSession(["abc123 123 cd", "abc"]); + + var search = new AceAjax.Search().set({ + needle: "\\d+", + regExp: true + }); + + var range = search.find(session); + assert.position(range.start, 0, 3); + assert.position(range.end, 0, 6); + }, + + "test: find using a regular expression and whole word": function () { + var session = new AceAjax.EditSession(["abc123 123 cd", "abc"]); + + var search = new AceAjax.Search().set({ + needle: "\\d+\\b", + regExp: true, + wholeWord: true + }); + + var range = search.find(session); + assert.position(range.start, 0, 7); + assert.position(range.end, 0, 10); + }, + + "test: use regular expressions with capture groups": function () { + var session = new AceAjax.EditSession([" ab: 12px", "

+ +exports = { + createSession: function (rows, cols) { + var line = new Array(cols + 1).join("a"); + var text = new Array(rows).join(line + "\n") + line; + return new AceAjax.EditSession(text); + }, + + "test: move cursor to end of file should place the cursor on last row and column": function () { + var session = this.createSession(200, 10); + var selection = session.getSelection(); + + selection.moveCursorFileEnd(); + assert.position(selection.getCursor(), 199, 10); + }, + + "test: moveCursor to start of file should place the cursor on the first row and column": function () { + var session = this.createSession(200, 10); + var selection = session.getSelection(); + + selection.moveCursorFileStart(); + assert.position(selection.getCursor(), 0, 0); + }, + + "test: move selection lead to end of file": function () { + var session = this.createSession(200, 10); + var selection = session.getSelection(); + + selection.moveCursorTo(100, 5); + selection.selectFileEnd(); + + var range = selection.getRange(); + + assert.position(range.start, 100, 5); + assert.position(range.end, 199, 10); + }, + + "test: move selection lead to start of file": function () { + var session = this.createSession(200, 10); + var selection = session.getSelection(); + + selection.moveCursorTo(100, 5); + selection.selectFileStart(); + + var range = selection.getRange(); + + assert.position(range.start, 0, 0); + assert.position(range.end, 100, 5); + }, + + "test: move cursor word right": function () { + var session = new AceAjax.EditSession([ + "ab", + " Juhu Kinners (abc, 12)", + " cde" + ].join("\n")); + + var selection = session.getSelection(); + + selection.moveCursorDown(); + assert.position(selection.getCursor(), 1, 0); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 1, 5); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 1, 13); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 1, 18); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 1, 22); + + // wrap line + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 2, 4); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 2, 4); + }, + + "test: select word right if cursor in word": function () { + var session = new AceAjax.EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 2); + selection.moveCursorWordRight(); + + assert.position(selection.getCursor(), 0, 4); + }, + + "test: moveCursor word left": function () { + var session = new AceAjax.EditSession([ + "ab", + " Juhu Kinners (abc, 12)", + " cde" + ].join("\n")); + + var selection = session.getSelection(); + + selection.moveCursorDown(); + selection.moveCursorLineEnd(); + assert.position(selection.getCursor(), 1, 23); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 1, 20); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 1, 15); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 1, 6); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 1, 1); + + // wrap line + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 0); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 0); + }, + + "test: moveCursor word left with umlauts": function () { + var session = new AceAjax.EditSession(" Fu Fe"); + + var selection = session.getSelection(); + selection.moveCursorTo(0, 9) + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 5); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 1); + }, + + "test: select word left if cursor in word": function () { + var session = new AceAjax.EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 8); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 5); + }, + + "test: select word right and select": function () { + var session = new AceAjax.EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 0); + selection.selectWordRight(); + + var range = selection.getRange(); + + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 4); + }, + + "test: select word left and select": function () { + var session = new AceAjax.EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 3); + selection.selectWordLeft(); + + var range = selection.getRange(); + + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 3); + }, + + "test: select word with cursor in word should select the word": function () { + var session = new AceAjax.EditSession("Juhu Kinners 123"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 8); + selection.selectWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 12); + }, + + "test: select word with cursor in word including right whitespace should select the word": function () { + var session = new AceAjax.EditSession("Juhu Kinners 123"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 8); + selection.selectAWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 18); + }, + + "test: select word with cursor betwen white space and word should select the word": function () { + var session = new AceAjax.EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 4); + selection.selectWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 4); + + selection.moveCursorTo(0, 5); + selection.selectWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 12); + }, + + "test: select word with cursor in white space should select white space": function () { + var session = new AceAjax.EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 5); + selection.selectWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 4); + assert.position(range.end, 0, 6); + }, + + "test: moving cursor should fire a 'changeCursor' event": function () { + var session = new AceAjax.EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 5); + + var called = false; + selection.addEventListener("changeCursor", function () { + called = true; + }); + + selection.moveCursorTo(0, 6); + assert.ok(called); + }, + + "test: calling setCursor with the same position should not fire an event": function () { + var session = new AceAjax.EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 5); + + var called = false; + selection.addEventListener("changeCursor", function () { + called = true; + }); + + selection.moveCursorTo(0, 5); + assert.notOk(called); + }, + + "test: moveWordright should move past || and [": function () { + var session = new AceAjax.EditSession("||foo["); + var selection = session.getSelection(); + + // Move behind ||foo + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 0, 5); + + // Move behind [ + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 0, 6); + }, + + "test: moveWordLeft should move past || and [": function () { + var session = new AceAjax.EditSession("||foo["); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 6); + + // Move behind [foo + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 2); + + // Move behind || + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 0); + }, + + "test: move cursor to line start should move cursor to end of the indentation first": function () { + var session = new AceAjax.EditSession("12\n Juhu\n12"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 6); + selection.moveCursorLineStart(); + + assert.position(selection.getCursor(), 1, 4); + }, + + "test: move cursor to line start when the cursor is at the end of the indentation should move cursor to column 0": function () { + var session = new AceAjax.EditSession("12\n Juhu\n12"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 4); + selection.moveCursorLineStart(); + + assert.position(selection.getCursor(), 1, 0); + }, + + "test: move cursor to line start when the cursor is at column 0 should move cursor to the end of the indentation": function () { + var session = new AceAjax.EditSession("12\n Juhu\n12"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 0); + selection.moveCursorLineStart(); + + assert.position(selection.getCursor(), 1, 4); + }, + + // Eclipse style + "test: move cursor to line start when the cursor is before the initial indentation should move cursor to the end of the indentation": function () { + var session = new AceAjax.EditSession("12\n Juhu\n12"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 2); + selection.moveCursorLineStart(); + + assert.position(selection.getCursor(), 1, 4); + }, + + "test go line up when in the middle of the first line should go to document start": function () { + var session = new AceAjax.EditSession("juhu kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 4); + selection.moveCursorUp(); + + assert.position(selection.getCursor(), 0, 0); + }, + + "test: (wrap) go line up when in the middle of the first line should go to document start": function () { + var session = new AceAjax.EditSession("juhu kinners"); + session.setWrapLimitRange(5, 5); + session.adjustWrapLimit(80); + + var selection = session.getSelection(); + + selection.moveCursorTo(0, 4); + selection.moveCursorUp(); + + assert.position(selection.getCursor(), 0, 0); + }, + + + "test go line down when in the middle of the last line should go to document end": function () { + var session = new AceAjax.EditSession("juhu kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 4); + selection.moveCursorDown(); + + assert.position(selection.getCursor(), 0, 12); + }, + + "test (wrap) go line down when in the middle of the last line should go to document end": function () { + var session = new AceAjax.EditSession("juhu kinners"); + session.setWrapLimitRange(8, 8); + session.adjustWrapLimit(80); + + var selection = session.getSelection(); + + selection.moveCursorTo(0, 10); + selection.moveCursorDown(); + + assert.position(selection.getCursor(), 0, 12); + }, + + "test go line up twice and then once down when in the second should go back to the previous column": function () { + var session = new AceAjax.EditSession("juhu\nkinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 4); + selection.moveCursorUp(); + selection.moveCursorUp(); + selection.moveCursorDown(); + + assert.position(selection.getCursor(), 1, 4); + }, + + "test (keyboard navigation) when curLine is not EOL and targetLine is all whitespace new column should be current column": function () { + var session = new AceAjax.EditSession("function (a) {\n\ + \n\ +}"); + var selection = session.getSelection(); + + selection.moveCursorTo(2, 0); + selection.moveCursorUp(); + + assert.position(selection.getCursor(), 1, 0); + }, + + "test (keyboard navigation) when curLine is EOL and targetLine is shorter dan current column, new column should be targetLine's EOL": function () { + var session = new AceAjax.EditSession("function (a) {\n\ + \n\ +}"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 14); + selection.moveCursorDown(); + + assert.position(selection.getCursor(), 1, 4); + } +}; diff --git a/ace/tests/ace-token_iterator-tests.ts b/ace/tests/ace-token_iterator-tests.ts new file mode 100644 index 000000000..75260e95a --- /dev/null +++ b/ace/tests/ace-token_iterator-tests.ts @@ -0,0 +1,166 @@ +/// + +exports = { + "test: token iterator initialization in JavaScript document": function () { + var lines = [ + "function foo(items) {", + " for (var i=0; i= 0; i--) + assert.equal(iterator.stepBackward(), tokens[i]); + assert.equal(iterator.stepBackward(), null); + assert.equal(iterator.getCurrentToken(), null); + }, + + "test: token iterator reports correct row and column": function () { + var lines = [ + "function foo(items) {", + " for (var i=0; i + +exports = { + "test: screen2text the column should be rounded to the next character edge": function () { + var el = document.createElement("div"); + + if (!el.getBoundingClientRect) { + console.log("Skipping test: This test only runs in the browser"); + return; + } + + el.style.left = "20px"; + el.style.top = "30px"; + el.style.width = "300px"; + el.style.height = "100px"; + document.body.appendChild(el); + + var renderer = new AceAjax.VirtualRenderer(el); + renderer.setPadding(0); + renderer.setSession(new AceAjax.EditSession("1234")); + + var r = renderer.scroller.getBoundingClientRect(); + function testPixelToText(x, y, row, column) { + assert.position(renderer.screenToTextCoordinates(x + r.left, y + r.top), row, column); + } + + renderer.characterWidth = 10; + renderer.lineHeight = 15; + + testPixelToText(4, 0, 0, 0); + testPixelToText(5, 0, 0, 1); + testPixelToText(9, 0, 0, 1); + testPixelToText(10, 0, 0, 1); + testPixelToText(14, 0, 0, 1); + testPixelToText(15, 0, 0, 2); + document.body.removeChild(el); + } + + // change tab size after setDocument (for text layer) +};