aboutsummaryrefslogtreecommitdiffstats
path: root/Source/CMTextView.m
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2009-04-02 01:23:26 +0000
committerrowanbeentje <rowan@beent.je>2009-04-02 01:23:26 +0000
commit00910549fefaaa0954aa080a3ec1be5a4746062b (patch)
tree896bc68f6426e58be635ef0238aad7b045057651 /Source/CMTextView.m
parent8fd7a25952b3d5317a22e14c83af06b56c32710a (diff)
downloadsequelpro-00910549fefaaa0954aa080a3ec1be5a4746062b.tar.gz
sequelpro-00910549fefaaa0954aa080a3ec1be5a4746062b.tar.bz2
sequelpro-00910549fefaaa0954aa080a3ec1be5a4746062b.zip
- Add a new "gear" action menu underneath the custom query view, including a number of items:
- Add menu commands for "Run All" and "Run Selected", with additional keyboard shortcuts - cmd-R for Run all, addressing #137 - Add menu commands for indenting text, outdenting text, and to show autocompletion is available - Add menu commands to toggle autopairing and autoindenting - Also hidden menu commands for history navigation and clearing, not hooked in yet (see #207) - Add a new method to our string additions: lineRangesForRange - Add "shift right" (indent) and "shift left" (outdent) support to CMTextView, including for multiple lines
Diffstat (limited to 'Source/CMTextView.m')
-rw-r--r--Source/CMTextView.m134
1 files changed, 130 insertions, 4 deletions
diff --git a/Source/CMTextView.m b/Source/CMTextView.m
index 2532cf1e..cfd42884 100644
--- a/Source/CMTextView.m
+++ b/Source/CMTextView.m
@@ -252,15 +252,18 @@ YY_BUFFER_STATE yy_scan_string (const char *);
{
// Handle newlines, adding any indentation found on the current line to the new line - ignoring the enter key if appropriate
- if (aSelector == @selector(insertNewline:) && (!autoindentIgnoresEnter || [[NSApp currentEvent] keyCode] != 0x4C)) {
+ if (aSelector == @selector(insertNewline:)
+ && autoindentEnabled
+ && (!autoindentIgnoresEnter || [[NSApp currentEvent] keyCode] != 0x4C))
+ {
NSString *textViewString = [[self textStorage] string];
NSString *currentLine, *indentString = nil;
NSScanner *whitespaceScanner;
- NSUInteger lineStart, lineEnd;
+ NSRange currentLineRange;
// Extract the current line based on the text caret or selection start position
- [textViewString getLineStart:&lineStart end:NULL contentsEnd:&lineEnd forRange:NSMakeRange([self selectedRange].location, 0)];
- currentLine = [[NSString alloc] initWithString:[textViewString substringWithRange:NSMakeRange(lineStart, lineEnd - lineStart)]];
+ currentLineRange = [textViewString lineRangeForRange:NSMakeRange([self selectedRange].location, 0)];
+ currentLine = [[NSString alloc] initWithString:[textViewString substringWithRange:currentLineRange]];
// Scan all indentation characters on the line into a string
whitespaceScanner = [[NSScanner alloc] initWithString:currentLine];
@@ -283,6 +286,129 @@ YY_BUFFER_STATE yy_scan_string (const char *);
/*
+ * Shifts the selection, if any, rightwards by indenting any selected lines with one tab.
+ * If the caret is within a line, the selection is not changed after the index; if the selection
+ * has length, all lines crossed by the length are indented and fully selected.
+ * Returns whether or not an indentation was performed.
+ */
+- (BOOL) shiftSelectionRight
+{
+ NSString *textViewString = [[self textStorage] string];
+ NSRange currentLineRange;
+ NSArray *lineRanges;
+ NSString *tabString = @"\t";
+ int i, indentedLinesLength = 0;
+
+ if ([self selectedRange].location == NSNotFound) return NO;
+
+ // Indent the currently selected line if the caret is within a single line
+ if ([self selectedRange].length == 0) {
+ NSRange currentLineRange;
+
+ // Extract the current line range based on the text caret
+ currentLineRange = [textViewString lineRangeForRange:[self selectedRange]];
+
+ // Register the indent for undo
+ [self shouldChangeTextInRange:NSMakeRange(currentLineRange.location, 0) replacementString:tabString];
+
+ // Insert the new tab
+ [self replaceCharactersInRange:NSMakeRange(currentLineRange.location, 0) withString:tabString];
+
+ return YES;
+ }
+
+ // Otherwise, the selection has a length - get an array of current line ranges for the specified selection
+ lineRanges = [textViewString lineRangesForRange:[self selectedRange]];
+
+ // Loop through the ranges, storing a count of the overall length.
+ for (i = 0; i < [lineRanges count]; i++) {
+ currentLineRange = NSRangeFromString([lineRanges objectAtIndex:i]);
+ indentedLinesLength += currentLineRange.length + 1;
+
+ // Register the indent for undo
+ [self shouldChangeTextInRange:NSMakeRange(currentLineRange.location+i, 0) replacementString:tabString];
+
+ // Insert the new tab
+ [self replaceCharactersInRange:NSMakeRange(currentLineRange.location+i, 0) withString:tabString];
+ }
+
+ // Select the entirety of the new range
+ [self setSelectedRange:NSMakeRange(NSRangeFromString([lineRanges objectAtIndex:0]).location, indentedLinesLength)];
+
+ return YES;
+}
+
+
+/*
+ * Shifts the selection, if any, leftwards by un-indenting any selected lines by one tab if possible.
+ * If the caret is within a line, the selection is not changed after the undent; if the selection has
+ * length, all lines crossed by the length are un-indented and fully selected.
+ * Returns whether or not an indentation was performed.
+ */
+- (BOOL) shiftSelectionLeft
+{
+ NSString *textViewString = [[self textStorage] string];
+ NSRange currentLineRange;
+ NSArray *lineRanges;
+ int i, unindentedLines = 0, unindentedLinesLength = 0;
+
+ if ([self selectedRange].location == NSNotFound) return NO;
+
+ // Undent the currently selected line if the caret is within a single line
+ if ([self selectedRange].length == 0) {
+ NSRange currentLineRange;
+
+ // Extract the current line range based on the text caret
+ currentLineRange = [textViewString lineRangeForRange:[self selectedRange]];
+
+ // Ensure that the line has length and that the first character is a tab
+ if (currentLineRange.length < 1
+ || [textViewString characterAtIndex:currentLineRange.location] != '\t')
+ return NO;
+
+ // Register the undent for undo
+ [self shouldChangeTextInRange:NSMakeRange(currentLineRange.location, 1) replacementString:@""];
+
+ // Remove the tab
+ [self replaceCharactersInRange:NSMakeRange(currentLineRange.location, 1) withString:@""];
+
+ return YES;
+ }
+
+ // Otherwise, the selection has a length - get an array of current line ranges for the specified selection
+ lineRanges = [textViewString lineRangesForRange:[self selectedRange]];
+
+ // Loop through the ranges, storing a count of the total lines changed and the new length.
+ for (i = 0; i < [lineRanges count]; i++) {
+ currentLineRange = NSRangeFromString([lineRanges objectAtIndex:i]);
+ unindentedLinesLength += currentLineRange.length;
+
+ // Ensure that the line has length and that the first character is a tab
+ if (currentLineRange.length < 1
+ || [textViewString characterAtIndex:currentLineRange.location-unindentedLines] != '\t')
+ continue;
+
+ // Register the undent for undo
+ [self shouldChangeTextInRange:NSMakeRange(currentLineRange.location-unindentedLines, 1) replacementString:@""];
+
+ // Remove the tab
+ [self replaceCharactersInRange:NSMakeRange(currentLineRange.location-unindentedLines, 1) withString:@""];
+
+ // As a line has been unindented, modify counts and lengths
+ unindentedLines++;
+ unindentedLinesLength--;
+ }
+
+ // If a change was made, select the entirety of the new range and return success
+ if (unindentedLines) {
+ [self setSelectedRange:NSMakeRange(NSRangeFromString([lineRanges objectAtIndex:0]).location, unindentedLinesLength)];
+ return YES;
+ }
+
+ return NO;
+}
+
+/*
* Handle autocompletion, returning a list of suggested completions for the supplied character range.
*/
- (NSArray *)completionsForPartialWordRange:(NSRange)charRange indexOfSelectedItem:(int *)index