| Line 25... |
Line 25... |
| 25 |
* http://www.gnu.org/copyleft/gpl.html. You can also obtain it by
|
25 |
* http://www.gnu.org/copyleft/gpl.html. You can also obtain it by
|
| 26 |
* writing to the Free Software Foundation, Inc., 59 Temple Place,
|
26 |
* writing to the Free Software Foundation, Inc., 59 Temple Place,
|
| 27 |
* Suite 330, Boston, MA 02111-1307 USA.
|
27 |
* Suite 330, Boston, MA 02111-1307 USA.
|
| 28 |
*
|
28 |
*
|
| 29 |
* Created by Simon Urbanek on 5/11/05.
|
29 |
* Created by Simon Urbanek on 5/11/05.
|
| 30 |
* $Id: RTextView.m 6438 2013-02-06 20:39:41Z urbaneks $
|
30 |
* $Id: RTextView.m 7927 2021-02-12 02:19:59Z urbaneks $
|
| 31 |
*/
|
31 |
*/
|
| 32 |
|
32 |
|
| 33 |
|
33 |
|
| 34 |
#import "RTextView.h"
|
34 |
#import "RTextView.h"
|
| 35 |
#import "HelpManager.h"
|
35 |
#import "HelpManager.h"
|
| Line 51... |
Line 51... |
| 51 |
static inline CGFloat RRectLeft(NSRect rectangle) { return rectangle.origin.x; }
|
51 |
static inline CGFloat RRectLeft(NSRect rectangle) { return rectangle.origin.x; }
|
| 52 |
static inline CGFloat RRectRight(NSRect rectangle) { return rectangle.origin.x+rectangle.size.width; }
|
52 |
static inline CGFloat RRectRight(NSRect rectangle) { return rectangle.origin.x+rectangle.size.width; }
|
| 53 |
static inline CGFloat RPointDistance(NSPoint a, NSPoint b) { return sqrtf( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) ); }
|
53 |
static inline CGFloat RPointDistance(NSPoint a, NSPoint b) { return sqrtf( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) ); }
|
| 54 |
static inline NSPoint RPointOnLine(NSPoint a, NSPoint b, CGFloat t) { return NSMakePoint(a.x*(1.0f-t) + b.x*t, a.y*(1.0f-t) + b.y*t); }
|
54 |
static inline NSPoint RPointOnLine(NSPoint a, NSPoint b, CGFloat t) { return NSMakePoint(a.x*(1.0f-t) + b.x*t, a.y*(1.0f-t) + b.y*t); }
|
| 55 |
|
55 |
|
| 56 |
static inline int RPARSERCONTEXTFORPOSITION (RTextView* self, NSUInteger index)
|
- |
|
| 57 |
{
|
- |
|
| 58 |
typedef int (*RPARSERCONTEXTFORPOSITIONMethodPtr)(RTextView*, SEL, NSUInteger);
|
- |
|
| 59 |
static RPARSERCONTEXTFORPOSITIONMethodPtr _RPARSERCONTEXTFORPOSITION;
|
- |
|
| 60 |
if (!_RPARSERCONTEXTFORPOSITION) _RPARSERCONTEXTFORPOSITION = (RPARSERCONTEXTFORPOSITIONMethodPtr)[self methodForSelector:@selector(parserContextForPosition:)];
|
- |
|
| 61 |
int r = _RPARSERCONTEXTFORPOSITION(self, @selector(parserContextForPosition:), index);
|
- |
|
| 62 |
return r;
|
- |
|
| 63 |
}
|
- |
|
| 64 |
|
- |
|
| 65 |
|
- |
|
| 66 |
// declared external
|
56 |
// declared external
|
| 67 |
BOOL RTextView_autoCloseBrackets = YES;
|
57 |
BOOL RTextView_autoCloseBrackets = YES;
|
| 68 |
|
58 |
|
| 69 |
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
|
59 |
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
|
| 70 |
// declare the following methods to avoid compiler warnings
|
60 |
// declare the following methods to avoid compiler warnings
|
| Line 80... |
Line 70... |
| 80 |
#pragma mark -
|
70 |
#pragma mark -
|
| 81 |
#pragma mark Private API
|
71 |
#pragma mark Private API
|
| 82 |
|
72 |
|
| 83 |
@interface RTextView (Private)
|
73 |
@interface RTextView (Private)
|
| 84 |
|
74 |
|
| 85 |
- (void)selectMatchingPairAt:(int)position;
|
75 |
- (void)selectMatchingPairAt:(NSInteger)position;
|
| 86 |
- (NSString*)functionNameForCurrentScope;
|
76 |
- (NSString*)functionNameForCurrentScope;
|
| 87 |
|
77 |
|
| 88 |
@end
|
78 |
@end
|
| 89 |
|
79 |
|
| 90 |
#pragma mark -
|
80 |
#pragma mark -
|
| Line 283... |
Line 273... |
| 283 |
return;
|
273 |
return;
|
| 284 |
}
|
274 |
}
|
| 285 |
|
275 |
|
| 286 |
NSString *rc = [theEvent charactersIgnoringModifiers];
|
276 |
NSString *rc = [theEvent charactersIgnoringModifiers];
|
| 287 |
NSString *cc = [theEvent characters];
|
277 |
NSString *cc = [theEvent characters];
|
| 288 |
unsigned int modFlags = [theEvent modifierFlags];
|
278 |
unsigned long modFlags = [theEvent modifierFlags];
|
| 289 |
long allFlags = (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask);
|
279 |
long allFlags = (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask);
|
| 290 |
long curFlags = (modFlags & allFlags);
|
280 |
long curFlags = (modFlags & allFlags);
|
| 291 |
|
281 |
|
| 292 |
BOOL hilite = NO;
|
282 |
BOOL hilite = NO;
|
| 293 |
|
283 |
|
| 294 |
SLog(@"RTextView: keyDown: %@ *** \"%@\" %d", theEvent, rc, modFlags);
|
284 |
SLog(@"RTextView: keyDown: %@ *** \"%@\" %lx", theEvent, rc, modFlags);
|
| 295 |
|
285 |
|
| 296 |
if([rc length] && [undoBreakTokensSet characterIsMember:[rc characterAtIndex:0]]) [self breakUndoCoalescing];
|
286 |
if([rc length] && [undoBreakTokensSet characterIsMember:[rc characterAtIndex:0]]) [self breakUndoCoalescing];
|
| 297 |
|
287 |
|
| 298 |
if ([rc isEqual:@"."] && (modFlags&allFlags)==NSControlKeyMask) {
|
288 |
if ([rc isEqual:@"."] && (modFlags&allFlags)==NSControlKeyMask) {
|
| 299 |
SLog(@" - send complete: to self");
|
289 |
SLog(@" - send complete: to self");
|
| 300 |
[self complete:self];
|
290 |
[self complete:self];
|
| 301 |
return;
|
291 |
return;
|
| 302 |
}
|
292 |
}
|
| 303 |
if ([rc isEqual:@"="]) {
|
293 |
if ([rc isEqual:@"="]) {
|
| 304 |
int mf = modFlags&allFlags;
|
294 |
long mf = modFlags & allFlags;
|
| 305 |
if ( mf ==NSControlKeyMask) {
|
295 |
if ( mf ==NSControlKeyMask) {
|
| 306 |
[self breakUndoCoalescing];
|
296 |
[self breakUndoCoalescing];
|
| 307 |
[self insertText:@"<-"];
|
297 |
[self insertText:@"<-"];
|
| 308 |
return;
|
298 |
return;
|
| 309 |
}
|
299 |
}
|
| Line 549... |
Line 539... |
| 549 |
/**
|
539 |
/**
|
| 550 |
* Returns the parser context for the passed cursor position
|
540 |
* Returns the parser context for the passed cursor position
|
| 551 |
*
|
541 |
*
|
| 552 |
* @param position The cursor position to test
|
542 |
* @param position The cursor position to test
|
| 553 |
*/
|
543 |
*/
|
| 554 |
- (int)parserContextForPosition:(int)position
|
544 |
- (int)parserContextForPosition:(NSInteger)position
|
| 555 |
{
|
545 |
{
|
| 556 |
|
546 |
|
| 557 |
int context = pcExpression;
|
547 |
int context = pcExpression;
|
| 558 |
|
548 |
|
| 559 |
if (position < 1)
|
549 |
if (position < 1)
|
| Line 572... |
Line 562... |
| 572 |
|
562 |
|
| 573 |
// we do NOT support multi-line strings, so the line always starts as an expression
|
563 |
// we do NOT support multi-line strings, so the line always starts as an expression
|
| 574 |
if (lineStart == position)
|
564 |
if (lineStart == position)
|
| 575 |
return context;
|
565 |
return context;
|
| 576 |
|
566 |
|
| 577 |
SLog(@"RTextView: parserContextForPosition: %d, line start: %ld", position, lineStart);
|
567 |
SLog(@"RTextView: parserContextForPosition: %ld, line start: %ld", (long)position, (long)lineStart);
|
| 578 |
|
568 |
|
| 579 |
int i = lineStart;
|
569 |
long i = lineStart;
|
| 580 |
BOOL skip = NO;
|
570 |
BOOL skip = NO;
|
| 581 |
unichar c;
|
571 |
unichar c;
|
| 582 |
unichar commentSign = (isRdDocument) ? '%' : '#';
|
572 |
unichar commentSign = (isRdDocument) ? '%' : '#';
|
| 583 |
|
573 |
|
| 584 |
while (i < position) {
|
574 |
while (i < position) {
|
| Line 976... |
Line 966... |
| 976 |
/**
|
966 |
/**
|
| 977 |
* Selects matching pairs if the character before position and at position are linked
|
967 |
* Selects matching pairs if the character before position and at position are linked
|
| 978 |
*
|
968 |
*
|
| 979 |
* @param position The cursor position to test
|
969 |
* @param position The cursor position to test
|
| 980 |
*/
|
970 |
*/
|
| 981 |
- (void)selectMatchingPairAt:(int)position
|
971 |
- (void)selectMatchingPairAt:(NSInteger)position
|
| 982 |
{
|
972 |
{
|
| 983 |
|
973 |
|
| 984 |
if(position < 1 || position >= [[self string] length])
|
974 |
if(position < 1 || position >= [[self string] length])
|
| 985 |
return;
|
975 |
return;
|
| 986 |
|
976 |
|
| Line 1015... |
Line 1005... |
| 1015 |
NSString *parseString = [self string];
|
1005 |
NSString *parseString = [self string];
|
| 1016 |
NSRange selectedRange = [self selectedRange];
|
1006 |
NSRange selectedRange = [self selectedRange];
|
| 1017 |
NSRange parseRange = NSMakeRange(0, [parseString length]);
|
1007 |
NSRange parseRange = NSMakeRange(0, [parseString length]);
|
| 1018 |
NSInteger breakCounter = 1000;
|
1008 |
NSInteger breakCounter = 1000;
|
| 1019 |
|
1009 |
|
| 1020 |
int parentheses = 0;
|
1010 |
int parentheses = 0;
|
| 1021 |
int index = 0;
|
1011 |
NSInteger index = 0;
|
| 1022 |
|
1012 |
|
| 1023 |
SLog(@"RTextView: functionNameForCurrentScope");
|
1013 |
SLog(@"RTextView: functionNameForCurrentScope");
|
| 1024 |
|
1014 |
|
| 1025 |
// if user selected something take the selection only; otherwise take the current word
|
1015 |
// if user selected something take the selection only; otherwise take the current word
|
| 1026 |
if (selectedRange.length) {
|
1016 |
if (selectedRange.length) {
|
| Line 1034... |
Line 1024... |
| 1034 |
SLog(@" - current word “%@”", helpString);
|
1024 |
SLog(@" - current word “%@”", helpString);
|
| 1035 |
|
1025 |
|
| 1036 |
// if a word was found and the word doesn't represent a numeric value
|
1026 |
// if a word was found and the word doesn't represent a numeric value
|
| 1037 |
// and a ( follows then return word
|
1027 |
// and a ( follows then return word
|
| 1038 |
if([helpString length] && ![[[NSNumber numberWithFloat:[helpString floatValue]] stringValue] isEqualToString:helpString]) {
|
1028 |
if([helpString length] && ![[[NSNumber numberWithFloat:[helpString floatValue]] stringValue] isEqualToString:helpString]) {
|
| 1039 |
int start = NSMaxRange(selectedRange);
|
1029 |
NSInteger start = NSMaxRange(selectedRange);
|
| 1040 |
if(start < [parseString length]) {
|
1030 |
if(start < [parseString length]) {
|
| 1041 |
BOOL found = NO;
|
1031 |
BOOL found = NO;
|
| 1042 |
int i = 0;
|
1032 |
NSInteger i = 0;
|
| 1043 |
int end = ([parseString length] > 100) ? 100 : [parseString length];
|
1033 |
NSInteger end = ([parseString length] > 100) ? 100 : [parseString length];
|
| 1044 |
unichar c;
|
1034 |
unichar c;
|
| 1045 |
for(i = start; i < end; i++) {
|
1035 |
for(i = start; i < end; i++) {
|
| 1046 |
if ((c = CFStringGetCharacterAtIndex((CFStringRef)parseString, i)) == '(') {
|
1036 |
if ((c = CFStringGetCharacterAtIndex((CFStringRef)parseString, i)) == '(') {
|
| 1047 |
found = YES;
|
1037 |
found = YES;
|
| 1048 |
break;
|
1038 |
break;
|
| Line 1101... |
Line 1091... |
| 1101 |
if(!found) {
|
1091 |
if(!found) {
|
| 1102 |
SLog(@" - parsing unsuccessfull; bail");
|
1092 |
SLog(@" - parsing unsuccessfull; bail");
|
| 1103 |
return nil;
|
1093 |
return nil;
|
| 1104 |
}
|
1094 |
}
|
| 1105 |
|
1095 |
|
| 1106 |
SLog(@" - first not closed ( found at index: %d", index);
|
1096 |
SLog(@" - first not closed ( found at index: %ld", (long) index);
|
| 1107 |
|
1097 |
|
| 1108 |
// check if we still are in the parse range; otherwise bail
|
1098 |
// check if we still are in the parse range; otherwise bail
|
| 1109 |
if(parseRange.location > index) {
|
1099 |
if(parseRange.location > index) {
|
| 1110 |
SLog(@" - found index invalid - bail");
|
1100 |
SLog(@" - found index invalid - bail");
|
| 1111 |
return nil;
|
1101 |
return nil;
|
| Line 1123... |
Line 1113... |
| 1123 |
break;
|
1113 |
break;
|
| 1124 |
}
|
1114 |
}
|
| 1125 |
}
|
1115 |
}
|
| 1126 |
}
|
1116 |
}
|
| 1127 |
|
1117 |
|
| 1128 |
SLog(@" - function name found at index: %d", index);
|
1118 |
SLog(@" - function name found at index: %ld", (long) index);
|
| 1129 |
|
1119 |
|
| 1130 |
// check if we still are in the parse range; otherwise bail
|
1120 |
// check if we still are in the parse range; otherwise bail
|
| 1131 |
if(parseRange.location > index) {
|
1121 |
if(parseRange.location > index) {
|
| 1132 |
SLog(@" - found index invalid - bail");
|
1122 |
SLog(@" - found index invalid - bail");
|
| 1133 |
return nil;
|
1123 |
return nil;
|
| Line 1185... |
Line 1175... |
| 1185 |
for (theCharIndex=0; theCharIndex<[strToConvert length]; theCharIndex++, theCharIndexInTextView++) {
|
1175 |
for (theCharIndex=0; theCharIndex<[strToConvert length]; theCharIndex++, theCharIndexInTextView++) {
|
| 1186 |
|
1176 |
|
| 1187 |
c = CFStringGetCharacterAtIndex((CFStringRef)strToConvert, theCharIndex);
|
1177 |
c = CFStringGetCharacterAtIndex((CFStringRef)strToConvert, theCharIndex);
|
| 1188 |
// if c is non-ASCII and inside of "" or '' quotes transform it
|
1178 |
// if c is non-ASCII and inside of "" or '' quotes transform it
|
| 1189 |
// - this ignores all c inside of comments
|
1179 |
// - this ignores all c inside of comments
|
| 1190 |
if (c > 127 && RPARSERCONTEXTFORPOSITION((RTextView*)self, theCharIndexInTextView) < pcStringBQ)
|
1180 |
if (c > 127 && [(RTextView*)self parserContextForPosition: theCharIndexInTextView] < pcStringBQ)
|
| 1191 |
[theEncodedString appendFormat: @"\\u%04x", c];
|
1181 |
[theEncodedString appendFormat: @"\\u%04x", c];
|
| 1192 |
else
|
1182 |
else
|
| 1193 |
[theEncodedString appendFormat: @"%C", c];
|
1183 |
[theEncodedString appendFormat: @"%C", c];
|
| 1194 |
|
1184 |
|
| 1195 |
}
|
1185 |
}
|
| Line 1248... |
Line 1238... |
| 1248 |
|
1238 |
|
| 1249 |
if ([menuItem action] == @selector(redo:))
|
1239 |
if ([menuItem action] == @selector(redo:))
|
| 1250 |
return ([[self undoManager] canRedo]);
|
1240 |
return ([[self undoManager] canRedo]);
|
| 1251 |
|
1241 |
|
| 1252 |
if ([menuItem action] == @selector(makeASCIIconform:))
|
1242 |
if ([menuItem action] == @selector(makeASCIIconform:))
|
| 1253 |
return ([self selectedRange].length || (([(RTextView*)self getRangeForCurrentWord].length) && RPARSERCONTEXTFORPOSITION((RTextView*)self, [self selectedRange].location) < pcStringBQ)) ? YES : NO;
|
1243 |
return ([self selectedRange].length || (([(RTextView*)self getRangeForCurrentWord].length) && [(RTextView*)self parserContextForPosition:[self selectedRange].location] < pcStringBQ)) ? YES : NO;
|
| 1254 |
|
1244 |
|
| 1255 |
if ([menuItem action] == @selector(unescapeUnicode:))
|
1245 |
if ([menuItem action] == @selector(unescapeUnicode:))
|
| 1256 |
return ([self selectedRange].length || ([(RTextView*)self getRangeForCurrentWord].length)) ? YES : NO;
|
1246 |
return ([self selectedRange].length || ([(RTextView*)self getRangeForCurrentWord].length)) ? YES : NO;
|
| 1257 |
|
1247 |
|
| 1258 |
return YES;
|
1248 |
return YES;
|
| Line 1359... |
Line 1349... |
| 1359 |
}
|
1349 |
}
|
| 1360 |
else {
|
1350 |
else {
|
| 1361 |
|
1351 |
|
| 1362 |
[env setObject:filepath forKey:kShellVarNameDraggedFilePath];
|
1352 |
[env setObject:filepath forKey:kShellVarNameDraggedFilePath];
|
| 1363 |
[env setObject:[[filepath stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"^%@", curDir] withString:@""] stringByAbbreviatingWithTildeInPath] forKey:kShellVarNameDraggedRelativeFilePath];
|
1353 |
[env setObject:[[filepath stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"^%@", curDir] withString:@""] stringByAbbreviatingWithTildeInPath] forKey:kShellVarNameDraggedRelativeFilePath];
|
| 1364 |
[env setObject:[NSNumber numberWithInt:snip_cnt] forKey:kShellVarNameCurrentSnippetIndex];
|
1354 |
[env setObject:[NSNumber numberWithInt:(int)snip_cnt] forKey:kShellVarNameCurrentSnippetIndex];
|
| 1365 |
|
1355 |
|
| 1366 |
NSString *extension = [[filepath pathExtension] lowercaseString];
|
1356 |
NSString *extension = [[filepath pathExtension] lowercaseString];
|
| 1367 |
|
1357 |
|
| 1368 |
// handle *.R for source()
|
1358 |
// handle *.R for source()
|
| 1369 |
if([extension isEqualToString:@"r"]) {
|
1359 |
if([extension isEqualToString:@"r"]) {
|
| Line 2132... |
Line 2122... |
| 2132 |
{
|
2122 |
{
|
| 2133 |
|
2123 |
|
| 2134 |
if (curRange.length) return curRange;
|
2124 |
if (curRange.length) return curRange;
|
| 2135 |
|
2125 |
|
| 2136 |
NSString *str = [self string];
|
2126 |
NSString *str = [self string];
|
| 2137 |
int curLocation = curRange.location;
|
2127 |
NSInteger curLocation = curRange.location;
|
| 2138 |
int start = curLocation;
|
2128 |
NSInteger start = curLocation;
|
| 2139 |
int end = curLocation;
|
2129 |
NSInteger end = curLocation;
|
| 2140 |
unsigned int strLen = [[self string] length];
|
2130 |
NSUInteger strLen = [[self string] length];
|
| 2141 |
|
2131 |
|
| 2142 |
if(start) {
|
2132 |
if(start) {
|
| 2143 |
start--;
|
2133 |
start--;
|
| 2144 |
if(CFStringGetCharacterAtIndex((CFStringRef)str, start) != '\n' || CFStringGetCharacterAtIndex((CFStringRef)str, start) != '\r') {
|
2134 |
if(CFStringGetCharacterAtIndex((CFStringRef)str, start) != '\n' || CFStringGetCharacterAtIndex((CFStringRef)str, start) != '\r') {
|
| 2145 |
while([wordCharSet characterIsMember:CFStringGetCharacterAtIndex((CFStringRef)str, start)]) {
|
2135 |
while([wordCharSet characterIsMember:CFStringGetCharacterAtIndex((CFStringRef)str, start)]) {
|