2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #import "SCTextView.h"
22 #import "MyDocument.h"
23 #import "SC_DirUtils.h"
25 #include "PyrSymbol.h"
28 extern bool compiledOK
;
29 //*)acceptableDragTypes
30 @implementation SCTextView
32 - (id)initWithFrame
:(NSRect
)frameRect
{
33 useAutoInOutdent
= false;
34 return [super initWithFrame
:frameRect
];
37 - (void) setLangClassToCall
: (NSString
*) stringin withKeyDownActionIndex
:(int) downIndex withKeyUpActionIndex
:(int) upIndex
39 langClassToCall
= stringin
;
40 keyDownActionIndex
= downIndex
;
41 keyUpActionIndex
= upIndex
;
42 [langClassToCall autorelease
];
45 - (void) setObjectKeyDownActionIndex
:(int) upindex setObjectKeyUpActionIndex
:(int) downindex
47 objectKeyDownActionIndex
= downindex
;
48 objectKeyUpActionIndex
= upindex
;
51 -(BOOL) acceptsFirstResponder
53 return mAcceptsFirstResponder
;
56 -(void) setAcceptsFirstResponder
: (BOOL) flag
58 mAcceptsFirstResponder
= flag
;
61 - (BOOL)becomeFirstResponder
63 BOOL accept
= [super becomeFirstResponder
];
64 if(accept
) [[self delegate
] setActiveTextView
: self];
68 - (void) setUsesAutoInOutdent
: (bool) flag
70 useAutoInOutdent
= flag
;
73 - (bool) usesAutoInOutdent
75 return useAutoInOutdent
;
78 - (void) autoIndent
: (NSEvent
*) event
83 NSRange range
= [self selectedRange
];
85 NSString
*string
= [self string
];
86 int pos
= range.location
;
89 c
= [string characterAtIndex
: --pos
];
90 if (c
== '\r' || c
== '\n') break;
91 if ((c
== '\t' || c
== ' ') && nspaces
< 126) spaces
[nspaces
++] = c
;
95 [super keyDown
: event
];
96 range
= [self selectedRange
];
98 string
= [self string
];
99 d
= [string characterAtIndex
: --pos
]; // did a newline actually get inserted? (maybe not if using foreign language input mode)
103 if(useAutoInOutdent
) {
105 d
= [string characterAtIndex
: --pos
];
107 spaces
[nspaces
++] = '\t';
111 if (d
== '\r' || d
== '\n' || d
== '}') break;
115 if (nspaces
&& (c
== '\r' || c
== '\n')) {
118 // reverse the string
119 for (int i
=0; i
<nspaces
/2; ++i
) {
121 spaces
[i
] = spaces
[nspaces
-1-i
];
122 spaces
[nspaces
-1-i
] = c
;
124 NSString
*newString
= [NSString stringWithCharacters
: spaces length
: nspaces
];
125 if ([self shouldChangeTextInRange
: range replacementString
: newString
]) {
126 [self replaceCharactersInRange
: range withString
: newString
];
127 [self didChangeText
];
132 - (NSString
*)currentlySelectedTextOrLine
: (NSRange
*) outRange
134 NSString
* string
= [self string
];
135 NSRange selectedRange
= [self selectedRange
];
136 if (selectedRange.length
<= 0) {
137 unsigned long lineStart
, lineEnd
;
138 [string getLineStart
: (NSUInteger
*)&lineStart end
: (NSUInteger
*)&lineEnd
139 contentsEnd
: nil forRange
:selectedRange
];
140 selectedRange
= NSMakeRange(lineStart
, lineEnd
- lineStart
);
142 if (outRange
) *outRange
= selectedRange
;
143 return [string substringWithRange
: selectedRange
];
146 - (NSString
*)currentlySelectedText
: (NSRange
*) outRange
148 NSString
* string
= [self string
];
149 NSRange selectedRange
= [self selectedRange
];
150 if (outRange
) *outRange
= selectedRange
;
151 return [string substringWithRange
: selectedRange
];
154 - (void) keyUp
: (NSEvent
*) event
156 NSString
*characters
= [event characters
];
158 unsigned int modifiers
= [event modifierFlags
];
159 unichar character
= 0;
160 if([characters length
] > 0) {
161 character
= [characters characterAtIndex
: 0];
163 unsigned int keycode
= [event keyCode
];
164 PyrObject
* pobj
= (PyrObject
*)[[self delegate
] getSCObject
];
166 pthread_mutex_lock (&gLangMutex
);
167 PyrSymbol
*documentclass
= getsym([langClassToCall cString
]);
168 PyrObject
*classobj
= (PyrObject
*) documentclass
->u.classobj
;
169 if(NotNil(pobj
->slots
+objectKeyUpActionIndex
) ||
NotNil(classobj
->slots
+keyUpActionIndex
)){
171 PyrSymbol
*method
= getsym("keyUp");
172 VMGlobals
*g
= gMainVMGlobals
;
174 ++g
->sp
; SetObject(g
->sp
, pobj
);
175 ++g
->sp
; SetChar(g
->sp
, character
);
176 ++g
->sp
; SetInt(g
->sp
, modifiers
);
177 ++g
->sp
; SetInt(g
->sp
, character
);
178 ++g
->sp
; SetInt(g
->sp
, keycode
);
179 runInterpreter(g
, method
, 5);
180 g
->canCallOS
= false;
183 pthread_mutex_unlock (&gLangMutex
);
186 if ([characters isEqual
: @
"\03"]) {
187 } else if (([characters isEqual
: @
"\n"] ||
[characters isEqual
: @
"\r"]) && !([event modifierFlags
] & NSAlternateKeyMask
)) {
189 [super keyUp
: event
];
193 - (void) keyDown
: (NSEvent
*) event
195 NSString
*characters
= [event characters
];
196 BOOL ignoreControlKeys
= NO
;
198 unsigned int modifiers
= [event modifierFlags
];
199 unichar character
= 0;
200 if([characters length
] > 0) {
201 character
= [characters characterAtIndex
: 0];
203 unsigned int keycode
= [event keyCode
];
205 PyrObject
* pobj
= (PyrObject
*)[[self delegate
] getSCObject
];
208 pthread_mutex_lock (&gLangMutex
);
209 PyrSymbol
*documentclass
= getsym([langClassToCall cString
]);
210 PyrObject
*classobj
= (PyrObject
*) documentclass
->u.classobj
;
211 if(NotNil(pobj
->slots
+objectKeyDownActionIndex
) ||
NotNil(classobj
->slots
+keyDownActionIndex
)){
213 PyrSymbol
*method
= getsym("keyDown");
214 VMGlobals
*g
= gMainVMGlobals
;
216 ++g
->sp
; SetObject(g
->sp
, pobj
);
217 ++g
->sp
; SetChar(g
->sp
, character
);
218 ++g
->sp
; SetInt(g
->sp
, modifiers
);
219 ++g
->sp
; SetInt(g
->sp
, character
);
220 ++g
->sp
; SetInt(g
->sp
, keycode
);
221 runInterpreter(g
, method
, 5);
222 g
->canCallOS
= false;
225 pthread_mutex_unlock (&gLangMutex
);
228 // shift- or control-return added by hjh
229 if ([characters isEqual
: @
"\03"] ||
230 (([characters isEqual
: @
"\n"] ||
[characters isEqual
: @
"\r"])
231 && ([event modifierFlags
] & (NSControlKeyMask | NSShiftKeyMask
)))) {
232 [[self delegate
] executeSelection
: self];
233 } else if (([characters isEqual
: @
"\n"] ||
[characters isEqual
: @
"\r"]) && !([event modifierFlags
] & NSAlternateKeyMask
)) {
234 [self autoIndent
: event
];
237 if([[self delegate
] handleKeyDown
: event
]) return;
238 if(ignoreControlKeys
&& ([event modifierFlags
] & NSCommandKeyMask
)) return;
239 [super keyDown
: event
];
241 if ([characters isEqual
: @
"}"] && useAutoInOutdent
) {
249 NSString
*string
= [self string
];
250 NSRange range
= [self selectedRange
];
251 int pos
= range.location
- 1;
255 // make sure I have only whitespace before me
257 c
= [string characterAtIndex
: --pos
];
258 if (c
== '\r' || c
== '\n') break;
259 if ((c
== '\t' || c
== ' ') && nspaces
< 126) nspaces
++;
262 if(nspaces
== 0) return; // bail
264 // okay now see if I have a matching bracket
265 unsigned int start
, end
;
266 start
= end
= range.location
- 1;
267 int length
= [string length
];
268 unichar
* buffer
= (unichar
*)malloc((length
+1) * sizeof(unichar
));
269 [string getCharacters
: buffer
];
271 if(!blankUnparsedChars(buffer
, end
, false))
272 blankUnparsedChars(buffer
, length
, true);
274 bool res
= matchBraks(&start
, &end
, buffer
, length
, '}', false);
276 if(!res
) return; // bail
281 c
= [string characterAtIndex
: --start
];
282 if (c
== '\r' || c
== '\n') break;
283 if ((c
== '\t' || c
== ' ') && nspaces
< 126) spaces
[nspaces
++] = c
;
287 c
= [string characterAtIndex
: pos
-1];
288 range
= NSMakeRange(pos
+ 1, range.location
- (pos
+ 2));
290 // if (nspaces && (c == '\r' || c == '\n')) {
293 // reverse the string
294 for (int i
=0; i
<nspaces
/2; ++i
) {
296 spaces
[i
] = spaces
[nspaces
-1-i
];
297 spaces
[nspaces
-1-i
] = c
;
299 NSString
*newString
= [NSString stringWithCharacters
: spaces length
: nspaces
];
300 if ([self shouldChangeTextInRange
: range replacementString
: newString
]) {
301 [self replaceCharactersInRange
: range withString
: newString
];
302 [self didChangeText
];
307 - (IBAction
) executeSelection
: (id) sender
{
308 [[self delegate
] executeSelection
: sender
];
311 bool matchBraks(unsigned int *startpos
, unsigned int *endpos
, unichar
*text
, int length
, unichar rightBrak
, bool ignoreImmediateParens
);
312 //-(void)rightMouseDown:(NSEvent*)theEvent { [[self delegate] mouseDown:theEvent]; [super rightMouseDown: theEvent]; }
313 //-(void)otherMouseDown:(NSEvent*)theEvent {[[self delegate] mouseDown:theEvent]; [super otherMouseDown: theEvent]; }
314 //-(void) mouseDragged:(NSEvent*)theEvent {[[self delegate] mouseDown:theEvent]; [super mouseDragged: theEvent]; }
315 -(BOOL) dragSelectionWithEvent
:(NSEvent
*)event offset
:(NSSize
)mouseOffset slideBack
:(BOOL)slideBack
317 [[self delegate
] mouseDown
:event
];
318 [super dragSelectionWithEvent
:event offset
:mouseOffset slideBack
:slideBack
];
320 - (void) mouseDown
: (NSEvent
*) event
322 NSWindow
*window
= [self window
];
323 NSPoint p
= [window convertBaseToScreen
: [event locationInWindow
]];
324 int index
= [self characterIndexForPoint
: p
];
325 if ([event clickCount
] == 2) {
326 NSString
*string
= [self string
];
327 int length
= [string length
];
328 if (index
< 0 || index
>= length
) { goto below
; }
329 unichar c
= [string characterAtIndex
: index
];
330 if (index
> 0 && (c
== '\n' || c
== '\r')) {
331 c
= [string characterAtIndex
: --index
];
333 if (c
== '(' || c
== ')' || c
== '[' || c
== ']' || c
== '{' || c
== '}') {
334 unsigned int start
, end
;
335 unichar
* buffer
= (unichar
*)malloc((length
+1) * sizeof(unichar
));
336 [string getCharacters
: buffer
];
337 if (c
== '[' || c
== '(' || c
== '{') {
338 start
= end
= index
+ 1;
339 } else if (c
== ']' || c
== ')' || c
== '}') {
343 if(!blankUnparsedChars(buffer
, end
, false))
344 blankUnparsedChars(buffer
, length
, true);
346 bool res
= matchBraks(&start
, &end
, buffer
, length
, 0, false);
349 NSRange newSelectedRange
= NSMakeRange(start
, end
- start
);
350 [self setSelectedRange
: newSelectedRange
];
356 [super mouseDown
: event
];
357 [self mouseUpAction
: event index
: index
];
358 [[self delegate
] mouseDown
: event
];
363 extern PyrSymbol
* s_mouseUp
;
364 - (void) mouseUpAction
: (NSEvent
*) theEvent index
: (int) index
370 unsigned int modifiers
= [theEvent modifierFlags
];
371 mouseLoc
= [self convertPoint
:[theEvent locationInWindow
] fromView
:nil];
372 // SCPoint scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
373 int clickCount
= [theEvent clickCount
];
374 int buttonNum
= [theEvent buttonNumber
];
375 pthread_mutex_lock (&gLangMutex
);
376 PyrObject
* pobj
= (PyrObject
*)[[self delegate
] getSCObject
];
378 VMGlobals
*g
= gMainVMGlobals
;
380 ++g
->sp
; SetObject(g
->sp
, pobj
);
381 ++g
->sp
; SetInt(g
->sp
, mouseLoc.x
);
382 ++g
->sp
; SetInt(g
->sp
, mouseLoc.y
);
383 ++g
->sp
; SetInt(g
->sp
, modifiers
);
384 ++g
->sp
; SetInt(g
->sp
,buttonNum
);
385 ++g
->sp
; SetInt(g
->sp
,clickCount
);
386 ++g
->sp
; SetInt(g
->sp
,index
);
387 runInterpreter(g
, s_mouseUp
, 7);
388 g
->canCallOS
= false;
390 pthread_mutex_unlock (&gLangMutex
);
392 - (void)setDefaultTabsTo
:(float)value
{
393 NSTextStorage
*text
= [self textStorage
];
394 int length
= [text length
], i
= 0;
397 NSMutableParagraphStyle
*style
= [[text attribute
: NSParagraphStyleAttributeName atIndex
: i longestEffectiveRange
: &range inRange
: NSMakeRange(0, [text length
])] mutableCopy
];
399 [style setDefaultTabInterval
: value
];
400 [text addAttribute
: NSParagraphStyleAttributeName value
: style range
: range
];
403 i
= i
+ range.length
;
407 // we need to override this because RTFfromRange converts relative links to http scheme links
408 // this makes a copy of selected text and converts links to absolute file scheme links
409 // when the target instance of MyDocument is saved it will convert any file scheme links back to relative
410 - (BOOL)writeSelectionToPasteboard
:(NSPasteboard
*)pboard type
:(NSString
*)type
{
412 MyDocument
*doc
= [[NSDocumentController sharedDocumentController
] documentForWindow
: [self window
]];
413 if(([type isEqualToString
:NSRTFPboardType
] ||
[type isEqualToString
:NSRTFDPboardType
]) && doc
){
414 NSRange range
= [self selectedRange
];
415 NSMutableAttributedString
*selectedText
= [[[self textStorage
] attributedSubstringFromRange
: range
] mutableCopy
];
418 while (range.length
> 0) {
419 id link
= [selectedText attribute
: NSLinkAttributeName
420 atIndex
: range.location
421 longestEffectiveRange
: &linkRange
423 if(linkRange.length
<=0) break;
424 if (link
&& [link isKindOfClass
: [NSString
class]] && (![link hasPrefix
:@
"SC://"] ||
![link hasPrefix
:@
"sc://"]) && ![link isAbsolutePath
]) {
425 // convert to a file:// URL
426 NSURL
*newLink
= [NSURL URLWithString
: [link stringByAddingPercentEscapesUsingEncoding
: NSUTF8StringEncoding
] relativeToURL
: [doc fileURL
]];
427 newLink
= [newLink absoluteURL
];
428 [selectedText addAttribute
: NSLinkAttributeName value
: newLink range
: linkRange
];
430 range
= NSMakeRange(NSMaxRange(linkRange
), NSMaxRange(range
) - NSMaxRange(linkRange
));
432 if([type isEqualToString
:NSRTFPboardType
]){
433 res
= [pboard setData
:[selectedText RTFFromRange
:NSMakeRange(0, [selectedText length
]) documentAttributes
:nil] forType
:NSRTFPboardType
];
434 } else if([type isEqualToString
:NSRTFDPboardType
]) {
435 res
= [pboard setData
:[selectedText RTFDFromRange
:NSMakeRange(0, [selectedText length
]) documentAttributes
:nil] forType
:NSRTFDPboardType
];
439 [selectedText release
];
441 res
= [super writeSelectionToPasteboard
:pboard type
:type
];
446 - (NSDragOperation
)draggingEntered
:(id < NSDraggingInfo
>)sender
{
447 NSDragOperation sourceDragMask
;
448 sourceDragMask
= [sender draggingSourceOperationMask
];
450 if(sourceDragMask
== NSDragOperationCopy
) { // we're holding the alt key
451 // block if we haven't been saved or aren't in a document
452 if(![[[NSDocumentController sharedDocumentController
] documentForWindow
: [self window
]] fileURL
]) {
453 return NSDragOperationNone
;
454 } else { return NSDragOperationCopy
; }
457 return [super draggingEntered
:sender
]; // pass on to NSTextView
460 NSString
* pathOfFileRelativeToBaseDir(NSString
*filepath
, NSString
*baseDir
); // from MyDocument.M
462 - (BOOL)performDragOperation
:(id <NSDraggingInfo
>)sender
{
463 NSPasteboard
*pboard
;
464 NSDragOperation sourceDragMask
;
466 sourceDragMask
= [sender draggingSourceOperationMask
];
467 pboard
= [sender draggingPasteboard
];
469 NSPoint mouseLoc
= [[self window
] convertBaseToScreen
:[sender draggingLocation
]];
470 unsigned int charIndex
= [self characterIndexForPoint
:mouseLoc
];
472 if ( [[pboard types
] containsObject
:NSFilenamesPboardType
] ) {
473 NSArray
*files
= [pboard propertyListForType
:NSFilenamesPboardType
];
474 NSEnumerator
*enumerator
= [files objectEnumerator
];
476 NSString
*filesString
= @
"", *docDir
;
477 BOOL commaSpace
= NO
;
478 BOOL alt
= (sourceDragMask
== NSDragOperationCopy
);
479 // we already checked in draggingEntered if this is in a document
480 if(alt
) docDir
= [[[[[NSDocumentController sharedDocumentController
] documentForWindow
: [self window
]] fileURL
] path
] stringByDeletingLastPathComponent
];
481 while (anObject
= [enumerator nextObject
]) {
482 if(commaSpace
) filesString
= [filesString stringByAppendingString
:@
", "];
483 filesString
= [filesString stringByAppendingString
:@
"\""];
484 if(alt
) anObject
= pathOfFileRelativeToBaseDir(anObject
, docDir
); // convert to relative
485 filesString
= [filesString stringByAppendingString
:anObject
];
486 filesString
= [filesString stringByAppendingString
:@
"\""];
487 if(alt
) filesString
= [filesString stringByAppendingString
:@
".resolveRelative"];
490 if([files count
] > 1) filesString
= [[@
"[" stringByAppendingString
:filesString
] stringByAppendingString
:@
"]"];
492 if ([self shouldChangeTextInRange
:NSMakeRange(charIndex
, 0) replacementString
:filesString
]) {
493 [[self textStorage
] replaceCharactersInRange
:NSMakeRange(charIndex
, 0) withString
:filesString
];
494 [self setSelectedRange
:NSMakeRange(charIndex
, [filesString length
])];
495 [self didChangeText
];
499 return [super performDragOperation
:sender
];
502 #define GETTEXTCHAR(pos, text, textlen) (((int)pos<0) ? 0 : (((int)pos>=(int)textlen) ? 0 : text[pos]))
504 unichar braks
[MAXBRAX
];
507 bool checkBraks(unsigned int startpos
, unsigned int endpos
, unichar
*text
, int length
);
508 bool checkBraks(unsigned int startpos
, unsigned int endpos
, unichar
*text
, int length
)
515 for (; pos
< endpos
; ++pos
) {
516 c
= GETTEXTCHAR(pos
, text
, length
);
517 if (c
== 0) return false;
520 if (brakptr
+1 < MAXBRAX
) {
521 braks
[brakptr
++] = ')';
523 } else if (c
== '[') {
524 if (brakptr
+1 < MAXBRAX
) {
525 braks
[brakptr
++] = ']';
527 } else if (c
== '{') {
528 if (brakptr
+1 < MAXBRAX
) {
529 braks
[brakptr
++] = '}';
531 } else if (c
== ')' || c
== ']' || c
== '}') {
533 if (braks
[--brakptr
] != c
) return false;
540 //bool matchBraks(unsigned int *startpos, unsigned int *endpos, unichar *text, int length, unichar rightBrak, bool ignoreImmediateParens);
541 bool matchBraks(unsigned int *startpos
, unsigned int *endpos
, unichar
*text
, int length
, unichar rightBrak
, bool ignoreImmediateParens
)
545 // check selection internally
546 if (!rightBrak
&& *endpos
> *startpos
&& !checkBraks(*startpos
, *endpos
, text
, length
)) return false;
548 c
= GETTEXTCHAR(((*startpos
)-1), text
, length
);
549 d
= GETTEXTCHAR(*endpos
, text
, length
);
551 if (ignoreImmediateParens
) {
552 if ((c
== '(' || c
== '[' || c
== '{') && (d
== ')' || d
== ']' || d
== '}')) {
553 // if selection is bounded by brackets but they do not match then fail
554 if (!((c
== '(' && d
== ')') ||
(c
== '[' && d
== ']') ||
(c
== '{' && d
== '}'))) {
557 // else expand selection by one before searching for next outer pair
571 c
= GETTEXTCHAR(*startpos
, text
, length
);
573 if (brakptr
+1 < MAXBRAX
) {
574 braks
[brakptr
++] = '(';
576 } else if (c
== ']') {
577 if (brakptr
+1 < MAXBRAX
) {
578 braks
[brakptr
++] = '[';
580 } else if (c
== '}') {
581 if (brakptr
+1 < MAXBRAX
) {
582 braks
[brakptr
++] = '{';
584 } else if (c
== '(' || c
== '[' || c
== '{') {
586 if (braks
[--brakptr
] != c
) return false;
590 if (c
== 0) return false;
594 d
= GETTEXTCHAR(*endpos
, text
, length
);
597 if (brakptr
+1 < MAXBRAX
) {
598 braks
[brakptr
++] = ')';
600 } else if (d
== '[') {
601 if (brakptr
+1 < MAXBRAX
) {
602 braks
[brakptr
++] = ']';
604 } else if (d
== '{') {
605 if (brakptr
+1 < MAXBRAX
) {
606 braks
[brakptr
++] = '}';
608 } else if (d
== ')' || d
== ']' || d
== '}') {
610 if (braks
[--brakptr
] != d
) return false;
614 if (d
== 0) return false;
617 if (!((c
== '(' && d
== ')') ||
(c
== '[' && d
== ']') ||
(c
== '{' && d
== '}'))) {
622 // success. shrink selection by one.
630 bool blankUnparsedChars(unichar
* buffer
, int length
, bool process
)
635 bool blankNext
= false;
636 bool blankThis
= false;
638 bool isString
= false;
639 bool isSingleLineComment
= false;
640 bool isMultiLineComment
= false;
641 bool isSymbol
= false;
643 for(i
= 0;i
<length
;i
++) {
645 c
= GETTEXTCHAR(i
, buffer
, length
);
654 if(c
== '/' && !isString
&& !isSymbol
&& !isSingleLineComment
&& !isMultiLineComment
) {
655 unichar d
= GETTEXTCHAR(i
+1,buffer
,length
);
657 isSingleLineComment
= true;
660 isMultiLineComment
= true;
663 if(isSingleLineComment
&& c
== '\n')
664 isSingleLineComment
= false;
666 if(isMultiLineComment
&& c
== '*')
667 if(GETTEXTCHAR(i
+1,buffer
,length
) == '/')
668 isMultiLineComment
= false;
670 if(c
== '\"' && !isSingleLineComment
&& !isMultiLineComment
&& !isSymbol
)
671 isString
= !isString
;
673 if(c
== '\'' && !isSingleLineComment
&& !isMultiLineComment
&& !isString
)
674 isSymbol
= !isSymbol
;
684 if(process
&& (isString || isSingleLineComment || isMultiLineComment || isSymbol || blankThis
))
692 return blankNext || isString || isSingleLineComment || isMultiLineComment || isSymbol
;
695 - (void)balanceParens
: (id)sender
697 NSRange selectedRange
= [self selectedRange
];
698 NSString
*string
= [self string
];
700 int length
= [string length
];
701 unichar
* buffer
= (unichar
*)malloc((length
+1) * sizeof(unichar
));
702 [string getCharacters
: buffer
];
704 unsigned int start
, end
;
705 start
= selectedRange.location
;
706 end
= start
+ selectedRange.length
;
708 if(!blankUnparsedChars(buffer
, end
, false))
709 blankUnparsedChars(buffer
, length
, true);
711 bool res
= matchBraks(&start
, &end
, buffer
, length
, 0, true);
714 NSRange newSelectedRange
= NSMakeRange(start
, end
- start
);
715 [self setSelectedRange
: newSelectedRange
];
719 - (NSArray
*)completionsForPartialWordRange
:(NSRange
)charRange indexOfSelectedItem
:(NSInteger
*)index
721 if([self loadCompletionDict
]){
722 NSString
* queryStr
= [(NSAttributedString
*)[self attributedSubstringFromRange
:charRange
] string
];
723 // create an NSArray containing all object names which match the query
724 NSMutableArray
* completions
;
725 completions
= [[NSMutableArray alloc
] init
];
726 NSEnumerator
* enumerator
= [completionDict objectEnumerator
];
728 while(element
= (NSString
*)[enumerator nextObject
]){
729 //post("%s hasPrefix: %s\n", element, theStr);
730 if([element hasPrefix
: queryStr
]){
731 [completions addObject
: element
];
734 //post("completionDict filtered from %u to %u entries\n", [completionDict count], [completions count]);
735 // Also append natural-language possibilities:
736 [completions addObjectsFromArray
: [super completionsForPartialWordRange
: charRange indexOfSelectedItem
: index
]];
739 // no dict file, or failure - pass through to standard non-SC suggestions.
740 return [super completionsForPartialWordRange
: charRange indexOfSelectedItem
: index
];
744 - (bool) loadCompletionDict
746 // if nsarray looks already ready, then return true
747 if(completionDict
!= NULL
){
751 char* fpath
= (char*)malloc(PATH_MAX
);
752 if(fpath
==NULL
) return false;
754 sc_GetUserAppSupportDirectory(fpath
, PATH_MAX
);
755 strncat(fpath
, "/sclang_completion_dict", PATH_MAX
);
757 // if file not exists or not openable, return false
758 FILE* fp
= fopen(fpath
, "r");
761 //post("couldn't open dict file :(\n");
765 // each line in the file becomes an entry in our array
766 char* line
= (char*)malloc(100);
767 completionDict
= [[NSMutableArray alloc
] init
];
768 while( fgets(line
, 100, fp
) != NULL
){
769 if((line
[0] != '\0') && (line
[strlen(line
) - 1] == '\n')){
770 line
[strlen(line
) - 1] = '\0'; // rm trailing newline
773 [completionDict addObject
: [NSString stringWithCString
: line encoding
: [NSString defaultCStringEncoding
]]];
779 //post("completionDict contains %u entries\n", [completionDict count]);
784 - (IBAction
)openCode
:(id)sender
786 [[self delegate
] sendSelection
: "openCodeFile"];
789 - (IBAction
) showHelpFor
: (id) sender
791 [[self delegate
] sendSelection
: "showHelp"];
794 - (IBAction
)showHelpSearch
:(id)sender
{
795 [[self delegate
] sendSelection
: "showHelpSearch"];
798 - (IBAction
)methodTemplates
: (id)sender
800 [[self delegate
] sendSelection
: "methodTemplates"];
803 - (IBAction
)methodReferences
: (id)sender
805 [[self delegate
] sendSelection
: "methodReferences"];
808 - (void)print
:(id)sender
810 NSPrintInfo
*printInfo
= [[[NSPrintInfo sharedPrintInfo
] copy
] autorelease
];
814 [printInfo setHorizontalPagination
: NSFitPagination
];
815 [printInfo setHorizontallyCentered
: YES
];
816 [printInfo setVerticallyCentered
: NO
];
817 [[NSPrintOperation printOperationWithView
:self printInfo
:printInfo
] runOperation
];
821 // redirect here to allow SCViews to get Cmd-F
822 - (void)cmdF
:(id)sender
{
823 [[TextFinder sharedInstance
] orderFrontFindPanel
:sender
];