add alignCursors command (ctrl+alt+a)

This commit is contained in:
nightwing 2012-08-19 18:21:33 +04:00
commit 4e12d1c9b9
2 changed files with 139 additions and 19 deletions

View file

@ -74,11 +74,15 @@ exports.defaultCommands = [{
}, {
name: "splitIntoLines",
exec: function(editor) { editor.multiSelect.splitIntoLines(); },
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"},
bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"},
readonly: true
}, {
name: "alignCursors",
exec: function(editor) { editor.alignCursors(); },
bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"}
}];
// commands active in multiselect mode
// commands active only in multiselect mode
exports.multiSelectCommands = [{
name: "singleSelection",
bindKey: "esc",

View file

@ -3,7 +3,7 @@
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
@ -14,7 +14,7 @@
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@ -35,6 +35,7 @@ var Range = require("./range").Range;
var Selection = require("./selection").Selection;
var onMouseDown = require("./mouse/multi_select_handler").onMouseDown;
var event = require("./lib/event");
var lang = require("./lib/lang");
var commands = require("./commands/multi_select_commands");
exports.commands = commands.defaultCommands.concat(commands.multiSelectCommands);
@ -66,7 +67,7 @@ var EditSession = require("./edit_session").EditSession;
this.rangeList = null;
/** extension
* Selection.addRange(range, $blockChangeEvents)
* Selection.addRange(range, $blockChangeEvents)
* - range (Range): The new range to add
* - $blockChangeEvents (Boolean): Whether or not to block changing events
*
@ -113,7 +114,7 @@ var EditSession = require("./edit_session").EditSession;
range && this.fromOrientedRange(range);
};
/** extension
* Selection.substractPoint(pos) -> Range
* - pos (Range): The position to remove, as a `{row, column}` object
@ -129,7 +130,7 @@ var EditSession = require("./edit_session").EditSession;
};
/** extension
* Selection.mergeOverlappingRanges()
* Selection.mergeOverlappingRanges()
*
* Merges overlapping ranges ensuring consistency after changes
**/
@ -241,7 +242,7 @@ var EditSession = require("./edit_session").EditSession;
* - screenCursor (Cursor): The cursor to use
* - screenAnchor (Anchor): The anchor to use
* - includeEmptyLines (Boolean): If true, this includes ranges inside the block which are empty due to clipping
*
*
* Gets list of ranges composing rectangular block on the screen
*
**/
@ -313,9 +314,9 @@ var EditSession = require("./edit_session").EditSession;
// extend Editor
var Editor = require("./editor").Editor;
(function() {
/** extension
* Editor.updateSelectionMarkers()
* Editor.updateSelectionMarkers()
*
* Updates the cursor and marker layers.
**/
@ -343,7 +344,7 @@ var Editor = require("./editor").Editor;
};
/** extension
* Editor.removeSelectionMarker(range)
* Editor.removeSelectionMarker(range)
* - range (Range): The selection range added with [[Editor.addSelectionMarker `addSelectionMarker()`]].
*
* Removes the selection marker.
@ -431,7 +432,7 @@ var Editor = require("./editor").Editor;
};
/** extension
* Editor.forEachSelection(cmd, args)
* Editor.forEachSelection(cmd, args)
* - cmd (String): The command to execute
* - args (String): Any arguments for the command
*
@ -496,7 +497,7 @@ var Editor = require("./editor").Editor;
// todo this should change when paste becomes a command
this.onPaste = function(text) {
if (this.$readOnly)
if (this.$readOnly)
return;
this._emit("paste", text);
@ -551,7 +552,7 @@ var Editor = require("./editor").Editor;
// commands
/** extension
* Editor.selectMoreLines(dir, skip)
* Editor.selectMoreLines(dir, skip)
* - dir (Number): The direction of lines to select: -1 for up, 1 for down
* - skip (Boolean): If `true`, removes the active selection range
*
@ -596,10 +597,10 @@ var Editor = require("./editor").Editor;
};
/** extension
* Editor.transposeSelections(dir)
* Editor.transposeSelections(dir)
* - dir (Number): The direction to rotate selections
*
* Transposes the selected ranges.
* Transposes the selected ranges.
**/
this.transposeSelections = function(dir) {
var session = this.session;
@ -639,13 +640,13 @@ var Editor = require("./editor").Editor;
}
/** extension
* Editor.selectMore(dir, skip)
* Editor.selectMore(dir, skip)
* - dir (Number): The direction of lines to select: -1 for up, 1 for down
* - skip (Boolean): If `true`, removes the active selection range
*
* Finds the next occurence of text in an active selection and adds it to the selections.
**/
this.selectMore = function (dir, skip) {
this.selectMore = function(dir, skip) {
var session = this.session;
var sel = session.multiSelect;
@ -665,6 +666,121 @@ var Editor = require("./editor").Editor;
if (skip)
this.multiSelect.substractPoint(range.cursor);
};
/** extension
* Editor.alignCursors()
*
* aligns cursors or selected text
**/
this.alignCursors = function() {
var session = this.session;
var sel = session.multiSelect;
var ranges = sel.ranges;
if (!ranges.length) {
var range = this.selection.getRange();
var fr = range.start.row, lr = range.end.row;
var lines = this.session.doc.removeLines(fr, lr);
lines = this.$reAlignText(lines);
this.session.doc.insertLines(fr, lines);
range.start.column = 0;
range.end.column = lines[lines.length - 1].length;
this.selection.setRange(range);
} else {
// filter out ranges on same row
var row = -1;
var sameRowRanges = ranges.filter(function(r) {
if (r.cursor.row == row)
return true;
row = r.cursor.row;
});
sel.$onRemoveRange(sameRowRanges);
var maxCol = 0;
var minSpace = Infinity;
var spaceOffsets = ranges.map(function(r) {
var p = r.cursor;
var line = session.getLine(p.row);
var spaceOffset = line.substr(p.column).search(/\S/g);
if (spaceOffset == -1)
spaceOffset = 0;
if (p.column > maxCol)
maxCol = p.column;
if (spaceOffset < minSpace)
minSpace = spaceOffset;
return spaceOffset;
});
ranges.forEach(function(r, i) {
var p = r.cursor;
var l = maxCol - p.column;
var d = spaceOffsets[i] - minSpace;
if (l > d)
session.insert(p, lang.stringRepeat(" ", l - d));
else
session.remove(new Range(p.row, p.column, p.row, p.column - l + d));
r.start.column = r.end.column = maxCol;
r.start.row = r.end.row = p.row;
r.cursor = r.end;
});
sel.fromOrientedRange(ranges[0]);
this.renderer.updateCursor();
this.renderer.updateBackMarkers();
}
};
this.$reAlignText = function(lines) {
var isLeftAligned = true, isRightAligned = true;
var startW, textW, endW;
return lines.map(function(line) {
var m = line.match(/(\s*)(.*?)(\s*)([=:].*)/);
if (!m)
return [line];
if (startW == null) {
startW = m[1].length;
textW = m[2].length;
endW = m[3].length;
return m;
}
if (startW + textW + endW != m[1].length + m[2].length + m[3].length)
isRightAligned = false;
if (startW != m[1].length)
isLeftAligned = false;
if (startW > m[1].length)
startW = m[1].length;
if (textW < m[2].length)
textW = m[2].length;
if (endW > m[3].length)
endW = m[3].length;
return m;
}).map(isLeftAligned ? isRightAligned ? alignRight : alignLeft : unAlign);
function strRepeat(n, ch) {
return Array(n + 1).join(ch)
}
function alignLeft(m) {
return !m[2] ? m[0] : strRepeat(startW, " ") + m[2]
+ strRepeat(textW - m[2].length + endW, " ")
+ m[4].replace(/^([=:])\s+/, "$1 ")
}
function alignRight(m) {
return !m[2] ? m[0] : strRepeat(startW + textW - m[2].length, " ") + m[2]
+ strRepeat(endW, " ")
+ m[4].replace(/^([=:])\s+/, "$1 ")
}
function unAlign(m) {
return !m[2] ? m[0] : strRepeat(startW, " ") + m[2]
+ strRepeat(endW, " ")
+ m[4].replace(/^([=:])\s+/, "$1 ")
}
}
}).call(Editor.prototype);
@ -710,7 +826,7 @@ exports.onSessionChange = function(e) {
}
};
// MultiSelect(editor)
// MultiSelect(editor)
// adds multiple selection support to the editor
// (note: should be called only once for each editor instance)
function MultiSelect(editor) {