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
];
165 PyrObject
* pobj
= [[self delegate
] getSCObject
];
167 pthread_mutex_lock (&gLangMutex
);
168 PyrSymbol
*documentclass
= getsym([langClassToCall cString
]);
169 PyrObject
*classobj
= (PyrObject
*) documentclass
->u.classobj
;
170 if(NotNil(pobj
->slots
+objectKeyUpActionIndex
) ||
NotNil(classobj
->slots
+keyUpActionIndex
)){
172 PyrSymbol
*method
= getsym("keyUp");
173 VMGlobals
*g
= gMainVMGlobals
;
175 ++g
->sp
; SetObject(g
->sp
, pobj
);
176 ++g
->sp
; SetChar(g
->sp
, character
);
177 ++g
->sp
; SetInt(g
->sp
, modifiers
);
178 ++g
->sp
; SetInt(g
->sp
, character
);
179 ++g
->sp
; SetInt(g
->sp
, keycode
);
180 runInterpreter(g
, method
, 5);
181 g
->canCallOS
= false;
184 pthread_mutex_unlock (&gLangMutex
);
187 if ([characters isEqual
: @
"\03"]) {
188 } else if (([characters isEqual
: @
"\n"] ||
[characters isEqual
: @
"\r"]) && !([event modifierFlags
] & NSAlternateKeyMask
)) {
190 [super keyUp
: event
];
194 - (void) keyDown
: (NSEvent
*) event
196 NSString
*characters
= [event characters
];
197 BOOL ignoreControlKeys
= NO
;
199 unsigned int modifiers
= [event modifierFlags
];
200 unichar character
= 0;
201 if([characters length
] > 0) {
202 character
= [characters characterAtIndex
: 0];
204 unsigned int keycode
= [event keyCode
];
206 PyrObject
* pobj
= [[self delegate
] getSCObject
];
209 pthread_mutex_lock (&gLangMutex
);
210 PyrSymbol
*documentclass
= getsym([langClassToCall cString
]);
211 PyrObject
*classobj
= (PyrObject
*) documentclass
->u.classobj
;
212 if(NotNil(pobj
->slots
+objectKeyDownActionIndex
) ||
NotNil(classobj
->slots
+keyDownActionIndex
)){
214 PyrSymbol
*method
= getsym("keyDown");
215 VMGlobals
*g
= gMainVMGlobals
;
217 ++g
->sp
; SetObject(g
->sp
, pobj
);
218 ++g
->sp
; SetChar(g
->sp
, character
);
219 ++g
->sp
; SetInt(g
->sp
, modifiers
);
220 ++g
->sp
; SetInt(g
->sp
, character
);
221 ++g
->sp
; SetInt(g
->sp
, keycode
);
222 runInterpreter(g
, method
, 5);
223 g
->canCallOS
= false;
226 pthread_mutex_unlock (&gLangMutex
);
229 // shift- or control-return added by hjh
230 if ([characters isEqual
: @
"\03"] ||
231 (([characters isEqual
: @
"\n"] ||
[characters isEqual
: @
"\r"])
232 && ([event modifierFlags
] & (NSControlKeyMask | NSShiftKeyMask
)))) {
233 [[self delegate
] executeSelection
: self];
234 } else if (([characters isEqual
: @
"\n"] ||
[characters isEqual
: @
"\r"]) && !([event modifierFlags
] & NSAlternateKeyMask
)) {
235 [self autoIndent
: event
];
238 if([[self delegate
] handleKeyDown
: event
]) return;
239 if(ignoreControlKeys
&& ([event modifierFlags
] & NSCommandKeyMask
)) return;
240 [super keyDown
: event
];
242 if ([characters isEqual
: @
"}"] && useAutoInOutdent
) {
250 NSString
*string
= [self string
];
251 NSRange range
= [self selectedRange
];
252 int pos
= range.location
- 1;
256 // make sure I have only whitespace before me
258 c
= [string characterAtIndex
: --pos
];
259 if (c
== '\r' || c
== '\n') break;
260 if ((c
== '\t' || c
== ' ') && nspaces
< 126) nspaces
++;
263 if(nspaces
== 0) return; // bail
265 // okay now see if I have a matching bracket
266 unsigned int start
, end
;
267 start
= end
= range.location
- 1;
268 int length
= [string length
];
269 unichar
* buffer
= (unichar
*)malloc((length
+1) * sizeof(unichar
));
270 [string getCharacters
: buffer
];
272 if(!blankUnparsedChars(buffer
, end
, false))
273 blankUnparsedChars(buffer
, length
, true);
275 bool res
= matchBraks(&start
, &end
, buffer
, length
, '}', false);
277 if(!res
) return; // bail
282 c
= [string characterAtIndex
: --start
];
283 if (c
== '\r' || c
== '\n') break;
284 if ((c
== '\t' || c
== ' ') && nspaces
< 126) spaces
[nspaces
++] = c
;
288 c
= [string characterAtIndex
: pos
-1];
289 range
= NSMakeRange(pos
+ 1, range.location
- (pos
+ 2));
291 // if (nspaces && (c == '\r' || c == '\n')) {
294 // reverse the string
295 for (int i
=0; i
<nspaces
/2; ++i
) {
297 spaces
[i
] = spaces
[nspaces
-1-i
];
298 spaces
[nspaces
-1-i
] = c
;
300 NSString
*newString
= [NSString stringWithCharacters
: spaces length
: nspaces
];
301 if ([self shouldChangeTextInRange
: range replacementString
: newString
]) {
302 [self replaceCharactersInRange
: range withString
: newString
];
303 [self didChangeText
];
308 - (IBAction
) executeSelection
: (id) sender
{
309 [[self delegate
] executeSelection
: sender
];
312 bool matchBraks(unsigned int *startpos
, unsigned int *endpos
, unichar
*text
, int length
, unichar rightBrak
, bool ignoreImmediateParens
);
313 //-(void)rightMouseDown:(NSEvent*)theEvent { [[self delegate] mouseDown:theEvent]; [super rightMouseDown: theEvent]; }
314 //-(void)otherMouseDown:(NSEvent*)theEvent {[[self delegate] mouseDown:theEvent]; [super otherMouseDown: theEvent]; }
315 //-(void) mouseDragged:(NSEvent*)theEvent {[[self delegate] mouseDown:theEvent]; [super mouseDragged: theEvent]; }
316 -(BOOL) dragSelectionWithEvent
:(NSEvent
*)event offset
:(NSSize
)mouseOffset slideBack
:(BOOL)slideBack
318 [[self delegate
] mouseDown
:event
];
319 [super dragSelectionWithEvent
:event offset
:mouseOffset slideBack
:slideBack
];
321 - (void) mouseDown
: (NSEvent
*) event
323 NSWindow
*window
= [self window
];
324 NSPoint p
= [window convertBaseToScreen
: [event locationInWindow
]];
325 int index
= [self characterIndexForPoint
: p
];
326 if ([event clickCount
] == 2) {
327 NSString
*string
= [self string
];
328 int length
= [string length
];
329 if (index
< 0 || index
>= length
) { goto below
; }
330 unichar c
= [string characterAtIndex
: index
];
331 if (index
> 0 && (c
== '\n' || c
== '\r')) {
332 c
= [string characterAtIndex
: --index
];
334 if (c
== '(' || c
== ')' || c
== '[' || c
== ']' || c
== '{' || c
== '}') {
335 unsigned int start
, end
;
336 unichar
* buffer
= (unichar
*)malloc((length
+1) * sizeof(unichar
));
337 [string getCharacters
: buffer
];
338 if (c
== '[' || c
== '(' || c
== '{') {
339 start
= end
= index
+ 1;
340 } else if (c
== ']' || c
== ')' || c
== '}') {
344 if(!blankUnparsedChars(buffer
, end
, false))
345 blankUnparsedChars(buffer
, length
, true);
347 bool res
= matchBraks(&start
, &end
, buffer
, length
, 0, false);
350 NSRange newSelectedRange
= NSMakeRange(start
, end
- start
);
351 [self setSelectedRange
: newSelectedRange
];
357 [super mouseDown
: event
];
358 [self mouseUpAction
: event index
: index
];
359 [[self delegate
] mouseDown
: event
];
364 extern PyrSymbol
* s_mouseUp
;
365 - (void) mouseUpAction
: (NSEvent
*) theEvent index
: (int) index
371 unsigned int modifiers
= [theEvent modifierFlags
];
372 mouseLoc
= [self convertPoint
:[theEvent locationInWindow
] fromView
:nil];
373 // SCPoint scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
374 int clickCount
= [theEvent clickCount
];
375 int buttonNum
= [theEvent buttonNumber
];
376 pthread_mutex_lock (&gLangMutex
);
377 PyrObject
* pobj
= [[self delegate
] getSCObject
];
379 VMGlobals
*g
= gMainVMGlobals
;
381 ++g
->sp
; SetObject(g
->sp
, pobj
);
382 ++g
->sp
; SetInt(g
->sp
, mouseLoc.x
);
383 ++g
->sp
; SetInt(g
->sp
, mouseLoc.y
);
384 ++g
->sp
; SetInt(g
->sp
, modifiers
);
385 ++g
->sp
; SetInt(g
->sp
,buttonNum
);
386 ++g
->sp
; SetInt(g
->sp
,clickCount
);
387 ++g
->sp
; SetInt(g
->sp
,index
);
388 runInterpreter(g
, s_mouseUp
, 7);
389 g
->canCallOS
= false;
391 pthread_mutex_unlock (&gLangMutex
);
393 - (void)setDefaultTabsTo
:(float)value
{
394 NSTextStorage
*text
= [self textStorage
];
395 int length
= [text length
], i
= 0;
398 NSMutableParagraphStyle
*style
= [[text attribute
: NSParagraphStyleAttributeName atIndex
: i longestEffectiveRange
: &range inRange
: NSMakeRange(0, [text length
])] mutableCopy
];
400 [style setDefaultTabInterval
: value
];
401 [text addAttribute
: NSParagraphStyleAttributeName value
: style range
: range
];
404 i
= i
+ range.length
;
408 // we need to override this because RTFfromRange converts relative links to http scheme links
409 // this makes a copy of selected text and converts links to absolute file scheme links
410 // when the target instance of MyDocument is saved it will convert any file scheme links back to relative
411 - (BOOL)writeSelectionToPasteboard
:(NSPasteboard
*)pboard type
:(NSString
*)type
{
413 MyDocument
*doc
= [[NSDocumentController sharedDocumentController
] documentForWindow
: [self window
]];
414 if(([type isEqualToString
:NSRTFPboardType
] ||
[type isEqualToString
:NSRTFDPboardType
]) && doc
){
415 NSRange range
= [self selectedRange
];
416 NSMutableAttributedString
*selectedText
= [[[self textStorage
] attributedSubstringFromRange
: range
] mutableCopy
];
419 while (range.length
> 0) {
420 id link
= [selectedText attribute
: NSLinkAttributeName
421 atIndex
: range.location
422 longestEffectiveRange
: &linkRange
424 if(linkRange.length
<=0) break;
425 if (link
&& [link isKindOfClass
: [NSString
class]] && (![link hasPrefix
:@
"SC://"] ||
![link hasPrefix
:@
"sc://"]) && ![link isAbsolutePath
]) {
426 // convert to a file:// URL
427 NSURL
*newLink
= [NSURL URLWithString
: [link stringByAddingPercentEscapesUsingEncoding
: NSUTF8StringEncoding
] relativeToURL
: [doc fileURL
]];
428 newLink
= [newLink absoluteURL
];
429 [selectedText addAttribute
: NSLinkAttributeName value
: newLink range
: linkRange
];
431 range
= NSMakeRange(NSMaxRange(linkRange
), NSMaxRange(range
) - NSMaxRange(linkRange
));
433 if([type isEqualToString
:NSRTFPboardType
]){
434 res
= [pboard setData
:[selectedText RTFFromRange
:NSMakeRange(0, [selectedText length
]) documentAttributes
:nil] forType
:NSRTFPboardType
];
435 } else if([type isEqualToString
:NSRTFDPboardType
]) {
436 res
= [pboard setData
:[selectedText RTFDFromRange
:NSMakeRange(0, [selectedText length
]) documentAttributes
:nil] forType
:NSRTFDPboardType
];
440 [selectedText release
];
442 res
= [super writeSelectionToPasteboard
:pboard type
:type
];
447 - (NSDragOperation
)draggingEntered
:(id < NSDraggingInfo
>)sender
{
448 NSDragOperation sourceDragMask
;
449 sourceDragMask
= [sender draggingSourceOperationMask
];
451 if(sourceDragMask
== NSDragOperationCopy
) { // we're holding the alt key
452 // block if we haven't been saved or aren't in a document
453 if(![[[NSDocumentController sharedDocumentController
] documentForWindow
: [self window
]] fileURL
]) {
454 return NSDragOperationNone
;
455 } else { return NSDragOperationCopy
; }
458 return [super draggingEntered
:sender
]; // pass on to NSTextView
461 NSString
* pathOfFileRelativeToBaseDir(NSString
*filepath
, NSString
*baseDir
); // from MyDocument.M
463 - (BOOL)performDragOperation
:(id <NSDraggingInfo
>)sender
{
464 NSPasteboard
*pboard
;
465 NSDragOperation sourceDragMask
;
467 sourceDragMask
= [sender draggingSourceOperationMask
];
468 pboard
= [sender draggingPasteboard
];
470 NSPoint mouseLoc
= [[self window
] convertBaseToScreen
:[sender draggingLocation
]];
471 unsigned int charIndex
= [self characterIndexForPoint
:mouseLoc
];
473 if ( [[pboard types
] containsObject
:NSFilenamesPboardType
] ) {
474 NSArray
*files
= [pboard propertyListForType
:NSFilenamesPboardType
];
475 NSEnumerator
*enumerator
= [files objectEnumerator
];
477 NSString
*filesString
= @
"", *docDir
;
478 BOOL commaSpace
= NO
;
479 BOOL alt
= (sourceDragMask
== NSDragOperationCopy
);
480 // we already checked in draggingEntered if this is in a document
481 if(alt
) docDir
= [[[[[NSDocumentController sharedDocumentController
] documentForWindow
: [self window
]] fileURL
] path
] stringByDeletingLastPathComponent
];
482 while (anObject
= [enumerator nextObject
]) {
483 if(commaSpace
) filesString
= [filesString stringByAppendingString
:@
", "];
484 filesString
= [filesString stringByAppendingString
:@
"\""];
485 if(alt
) anObject
= pathOfFileRelativeToBaseDir(anObject
, docDir
); // convert to relative
486 filesString
= [filesString stringByAppendingString
:anObject
];
487 filesString
= [filesString stringByAppendingString
:@
"\""];
488 if(alt
) filesString
= [filesString stringByAppendingString
:@
".resolveRelative"];
491 if([files count
] > 1) filesString
= [[@
"[" stringByAppendingString
:filesString
] stringByAppendingString
:@
"]"];
493 if ([self shouldChangeTextInRange
:NSMakeRange(charIndex
, 0) replacementString
:filesString
]) {
494 [[self textStorage
] replaceCharactersInRange
:NSMakeRange(charIndex
, 0) withString
:filesString
];
495 [self setSelectedRange
:NSMakeRange(charIndex
, [filesString length
])];
496 [self didChangeText
];
500 return [super performDragOperation
:sender
];
503 #define GETTEXTCHAR(pos, text, textlen) (((int)pos<0) ? 0 : (((int)pos>=(int)textlen) ? 0 : text[pos]))
505 unichar braks
[MAXBRAX
];
508 bool checkBraks(unsigned int startpos
, unsigned int endpos
, unichar
*text
, int length
);
509 bool checkBraks(unsigned int startpos
, unsigned int endpos
, unichar
*text
, int length
)
516 for (; pos
< endpos
; ++pos
) {
517 c
= GETTEXTCHAR(pos
, text
, length
);
518 if (c
== 0) return false;
521 if (brakptr
+1 < MAXBRAX
) {
522 braks
[brakptr
++] = ')';
524 } else if (c
== '[') {
525 if (brakptr
+1 < MAXBRAX
) {
526 braks
[brakptr
++] = ']';
528 } else if (c
== '{') {
529 if (brakptr
+1 < MAXBRAX
) {
530 braks
[brakptr
++] = '}';
532 } else if (c
== ')' || c
== ']' || c
== '}') {
534 if (braks
[--brakptr
] != c
) return false;
541 //bool matchBraks(unsigned int *startpos, unsigned int *endpos, unichar *text, int length, unichar rightBrak, bool ignoreImmediateParens);
542 bool matchBraks(unsigned int *startpos
, unsigned int *endpos
, unichar
*text
, int length
, unichar rightBrak
, bool ignoreImmediateParens
)
546 // check selection internally
547 if (!rightBrak
&& *endpos
> *startpos
&& !checkBraks(*startpos
, *endpos
, text
, length
)) return false;
549 c
= GETTEXTCHAR(((*startpos
)-1), text
, length
);
550 d
= GETTEXTCHAR(*endpos
, text
, length
);
552 if (ignoreImmediateParens
) {
553 if ((c
== '(' || c
== '[' || c
== '{') && (d
== ')' || d
== ']' || d
== '}')) {
554 // if selection is bounded by brackets but they do not match then fail
555 if (!((c
== '(' && d
== ')') ||
(c
== '[' && d
== ']') ||
(c
== '{' && d
== '}'))) {
558 // else expand selection by one before searching for next outer pair
572 c
= GETTEXTCHAR(*startpos
, text
, length
);
574 if (brakptr
+1 < MAXBRAX
) {
575 braks
[brakptr
++] = '(';
577 } else if (c
== ']') {
578 if (brakptr
+1 < MAXBRAX
) {
579 braks
[brakptr
++] = '[';
581 } else if (c
== '}') {
582 if (brakptr
+1 < MAXBRAX
) {
583 braks
[brakptr
++] = '{';
585 } else if (c
== '(' || c
== '[' || c
== '{') {
587 if (braks
[--brakptr
] != c
) return false;
591 if (c
== 0) return false;
595 d
= GETTEXTCHAR(*endpos
, text
, length
);
598 if (brakptr
+1 < MAXBRAX
) {
599 braks
[brakptr
++] = ')';
601 } else if (d
== '[') {
602 if (brakptr
+1 < MAXBRAX
) {
603 braks
[brakptr
++] = ']';
605 } else if (d
== '{') {
606 if (brakptr
+1 < MAXBRAX
) {
607 braks
[brakptr
++] = '}';
609 } else if (d
== ')' || d
== ']' || d
== '}') {
611 if (braks
[--brakptr
] != d
) return false;
615 if (d
== 0) return false;
618 if (!((c
== '(' && d
== ')') ||
(c
== '[' && d
== ']') ||
(c
== '{' && d
== '}'))) {
623 // success. shrink selection by one.
631 bool blankUnparsedChars(unichar
* buffer
, int length
, bool process
)
636 bool blankNext
= false;
637 bool blankThis
= false;
639 bool isString
= false;
640 bool isSingleLineComment
= false;
641 bool isMultiLineComment
= false;
642 bool isSymbol
= false;
644 for(i
= 0;i
<length
;i
++) {
646 c
= GETTEXTCHAR(i
, buffer
, length
);
655 if(c
== '/' && !isString
&& !isSymbol
&& !isSingleLineComment
&& !isMultiLineComment
) {
656 unichar d
= GETTEXTCHAR(i
+1,buffer
,length
);
658 isSingleLineComment
= true;
661 isMultiLineComment
= true;
664 if(isSingleLineComment
&& c
== '\n')
665 isSingleLineComment
= false;
667 if(isMultiLineComment
&& c
== '*')
668 if(GETTEXTCHAR(i
+1,buffer
,length
) == '/')
669 isMultiLineComment
= false;
671 if(c
== '\"' && !isSingleLineComment
&& !isMultiLineComment
&& !isSymbol
)
672 isString
= !isString
;
674 if(c
== '\'' && !isSingleLineComment
&& !isMultiLineComment
&& !isString
)
675 isSymbol
= !isSymbol
;
685 if(process
&& (isString || isSingleLineComment || isMultiLineComment || isSymbol || blankThis
))
693 return blankNext || isString || isSingleLineComment || isMultiLineComment || isSymbol
;
696 - (void)balanceParens
: (id)sender
698 NSRange selectedRange
= [self selectedRange
];
699 NSString
*string
= [self string
];
701 int length
= [string length
];
702 unichar
* buffer
= (unichar
*)malloc((length
+1) * sizeof(unichar
));
703 [string getCharacters
: buffer
];
705 unsigned int start
, end
;
706 start
= selectedRange.location
;
707 end
= start
+ selectedRange.length
;
709 if(!blankUnparsedChars(buffer
, end
, false))
710 blankUnparsedChars(buffer
, length
, true);
712 bool res
= matchBraks(&start
, &end
, buffer
, length
, 0, true);
715 NSRange newSelectedRange
= NSMakeRange(start
, end
- start
);
716 [self setSelectedRange
: newSelectedRange
];
720 - (NSArray
*)completionsForPartialWordRange
:(NSRange
)charRange indexOfSelectedItem
:(NSInteger
*)index
722 if([self loadCompletionDict
]){
723 NSString
* queryStr
= [(NSAttributedString
*)[self attributedSubstringFromRange
:charRange
] string
];
724 // create an NSArray containing all object names which match the query
725 NSMutableArray
* completions
;
726 completions
= [[NSMutableArray alloc
] init
];
727 NSEnumerator
* enumerator
= [completionDict objectEnumerator
];
729 while(element
= (NSString
*)[enumerator nextObject
]){
730 //post("%s hasPrefix: %s\n", element, theStr);
731 if([element hasPrefix
: queryStr
]){
732 [completions addObject
: element
];
735 //post("completionDict filtered from %u to %u entries\n", [completionDict count], [completions count]);
736 // Also append natural-language possibilities:
737 [completions addObjectsFromArray
: [super completionsForPartialWordRange
: charRange indexOfSelectedItem
: index
]];
740 // no dict file, or failure - pass through to standard non-SC suggestions.
741 return [super completionsForPartialWordRange
: charRange indexOfSelectedItem
: index
];
745 - (bool) loadCompletionDict
747 // if nsarray looks already ready, then return true
748 if(completionDict
!= NULL
){
752 char* fpath
= (char*)malloc(PATH_MAX
);
753 if(fpath
==NULL
) return false;
755 sc_GetUserAppSupportDirectory(fpath
, PATH_MAX
);
756 strncat(fpath
, "/sclang_completion_dict", PATH_MAX
);
758 // if file not exists or not openable, return false
759 FILE* fp
= fopen(fpath
, "r");
762 //post("couldn't open dict file :(\n");
766 // each line in the file becomes an entry in our array
767 char* line
= (char*)malloc(100);
768 completionDict
= [[NSMutableArray alloc
] init
];
769 while( fgets(line
, 100, fp
) != NULL
){
770 if((line
[0] != '\0') && (line
[strlen(line
) - 1] == '\n')){
771 line
[strlen(line
) - 1] = '\0'; // rm trailing newline
774 [completionDict addObject
: [NSString stringWithCString
: line encoding
: [NSString defaultCStringEncoding
]]];
780 //post("completionDict contains %u entries\n", [completionDict count]);
785 - (IBAction
)openCode
:(id)sender
787 [[self delegate
] sendSelection
: "openCodeFile"];
790 - (IBAction
) showHelpFor
: (id) sender
792 [[self delegate
] sendSelection
: "showHelp"];
795 - (IBAction
)showHelpSearch
:(id)sender
{
796 [[self delegate
] sendSelection
: "showHelpSearch"];
799 - (IBAction
)methodTemplates
: (id)sender
801 [[self delegate
] sendSelection
: "methodTemplates"];
804 - (IBAction
)methodReferences
: (id)sender
806 [[self delegate
] sendSelection
: "methodReferences"];
809 - (void)print
:(id)sender
811 NSPrintInfo
*printInfo
= [[[NSPrintInfo sharedPrintInfo
] copy
] autorelease
];
815 [printInfo setHorizontalPagination
: NSFitPagination
];
816 [printInfo setHorizontallyCentered
: YES
];
817 [printInfo setVerticallyCentered
: NO
];
818 [[NSPrintOperation printOperationWithView
:self printInfo
:printInfo
] runOperation
];