Skip to content
Browse files

Updated Select Column action to calculate how many space characters t…

…abs are visually occupying, and adjust accordingly
  • Loading branch information...
1 parent 8a7ed03 commit ffbec41c15a24cc5eaad82abd1178d35d5a7d6b8 @onecrayon committed Mar 12, 2013
Showing with 86 additions and 16 deletions.
  1. +86 −16 Scripts/select-column.js
View
102 Scripts/select-column.js
@@ -6,44 +6,114 @@
*
* setup:
* - direction (string): 'up' or 'down'
- *
- * FIXME: currently, this does not take into account the fact that tab
- * characters visually consume extra space, so if you run it along lines
- * that have different amounts of tab indentation, you get odd-looking
- * results. Need to figure out a way to deal with this, but JS API does
- * not currently have access to preference information about how many
- * spaces a tab represents, so it's a bit of a quandary unless I convert
- * it to Objective-C.
*/
-action.canPerformWithContext= function(context, outError) {
+action.canPerformWithContext = function(context, outError) {
return action.setup.direction && context.selectedRanges[0].length > 0;
};
-action.performWithContext= function(context, outError) {
+action.performWithContext = function(context, outError) {
// Determine which direction we are going and setup initial variables
var dir = (action.setup.direction.toLowerCase() === 'up' ? -1 : 1),
whitespaceRE = /^\s+$/,
startRange = (dir === 1 ? context.selectedRanges[context.selectedRanges.length - 1] : context.selectedRanges[0]),
selectWhitespace = whitespaceRE.test(context.substringWithRange(startRange)),
startLineNumber = context.lineStorage.lineNumberForIndex(startRange.location),
- startLineRange = context.lineStorage.lineRangeForLineNumber(startLineNumber),
- startLineOffset = startRange.location - startLineRange.location,
- targetLineNumber = startLineNumber + dir,
- targetLineRange, nextSelectionRange = null;
+ startLineRange = context.lineStorage.lineRangeForLineNumber(startLineNumber);
// Don't bother trying to process if our target selection spans more than one line
if (startRange.location + startRange.length > startLineRange.location + startLineRange.length) {
return false;
}
+
+ // Figure out our offsets, adjusted for tab characters
+ var spacesPerTab = context.textPreferences.numberOfSpacesForTab,
+ startLineParts = context.substringWithRange(startLineRange).split('\t'),
+ startLineStart = null, startLineEnd = null, curString = '', curAdjustedIndex = 0, curSegment = '';
+ for (var i = 0, count = startLineParts.length; i < count; i++) {
+ if (i > 0) {
+ curString += '\t';
+ // Tabs consume enough spaces to bring them up to the next grid space, so we use the remainder to figure out how many spaces they actually take up
+ curAdjustedIndex += spacesPerTab - (curAdjustedIndex % spacesPerTab);
+ }
+ curSegment = startLineParts[i];
+ if (startLineStart === null) {
+ if (curString.length === startRange.location - startLineRange.location) {
+ // Start index falls on a tab
+ startLineStart = curAdjustedIndex;
+ } else if (startRange.location - startLineRange.location <= curString.length + curSegment.length) {
+ // Start index falls within the upcoming segment
+ startLineStart = curAdjustedIndex + (startRange.location - startLineRange.location - curString.length);
+ }
+ }
+ if (startLineEnd === null) {
+ if (curString.length === startRange.location + startRange.length) {
+ // End index falls at the end of this tab
+ startLineEnd = curAdjustedIndex;
+ } else if ((startRange.location + startRange.length) - startLineRange.location <= curString.length + curSegment.length) {
+ // End index falls in the upcoming segment somewhere
+ startLineEnd = curAdjustedIndex + ((startRange.location + startRange.length) - startLineRange.location - curString.length);
+ }
+ }
+ if (startLineStart === null || startLineEnd === null) {
+ curString += curSegment;
+ curAdjustedIndex += curSegment.length;
+ } else {
+ break;
+ }
+ }
+
+ var targetLineNumber = startLineNumber + dir,
+ targetLineRange, nextSelectionRange = null, targetLineParts = [], targetLineConverted = '';
// Parse through the lines to look for the first one that we can select
while (targetLineNumber > 0 && targetLineNumber <= context.lineStorage.numberOfLines) {
targetLineRange = context.lineStorage.lineRangeForLineNumber(targetLineNumber);
+ targetLineParts = context.substringWithRange(targetLineRange).split('\t');
+ targetLineConverted = targetLineParts.join(new Array(spacesPerTab + 1).join(' '));
// Skip ahead if the line is nothing but whitespace (unless our original selection was nothing but whitespace) or if it isn't long enough
- if ((!selectWhitespace && whitespaceRE.test(context.substringWithRange(targetLineRange))) || targetLineRange.location + targetLineRange.length < startLineOffset + startRange.length || (!selectWhitespace && whitespaceRE.test(context.substringWithRange(new Range(targetLineRange.location + startLineOffset, startRange.length))))) {
+ if ((!selectWhitespace && whitespaceRE.test(targetLineConverted)) || targetLineConverted.length < startLineEnd || (!selectWhitespace && whitespaceRE.test(targetLineConverted.substring(startLineStart, startLineEnd)))) {
targetLineNumber += dir;
continue;
} else {
- nextSelectionRange = new Range(targetLineRange.location + startLineOffset, startRange.length);
+ var targetStart = null, targetEnd = null;
+ curAdjustedIndex = 0;
+ curString = '';
+ curSegment = '';
+ for (i = 0, count = targetLineParts.length; i < count; i++) {
+ if (i > 0) {
+ curString += '\t';
+ // Tabs consume enough spaces to bring them up to the next grid space, so we use the remainder to figure out how many spaces they actually take up
+ curAdjustedIndex += spacesPerTab - (curAdjustedIndex % spacesPerTab);
+ }
+ curSegment = targetLineParts[i];
+ if (targetStart === null) {
+ if (curAdjustedIndex >= startLineStart) {
+ // The start offset fell somewhere in the middle of a tab, so adjust to the end of the tab
+ targetStart = curString.length;
+ } else if (startLineStart <= curAdjustedIndex + curSegment.length) {
+ // Start index falls somewhere in our current segment
+ targetStart = curString.length + (startLineStart - curAdjustedIndex);
+ }
+ }
+ if (targetEnd === null) {
+ if (curAdjustedIndex >= startLineEnd) {
+ // End index falls in the middle of a tab; wrap the tab
+ targetEnd = curString.length - targetStart;
+ } else if (startLineEnd <= curAdjustedIndex + curSegment.length) {
+ // End index falls somewhere in our current segment
+ targetEnd = curString.length + (startLineEnd - curAdjustedIndex);
+ }
+ }
+ if (targetStart === null || targetEnd === null) {
+ curString += curSegment;
+ curAdjustedIndex += curSegment.length;
+ } else {
+ break;
+ }
+ }
+ if (targetEnd === null) {
+ targetEnd = curString.length;
+ }
+ nextSelectionRange = new Range(targetLineRange.location + targetStart, targetEnd - targetStart);
break;
}
}

0 comments on commit ffbec41

Please sign in to comment.
Something went wrong with that request. Please try again.