apps-projectcenter/Modules/Editors/ProjectCenter/PCEditor+Document.m

322 lines
8.3 KiB
Mathematica
Raw Normal View History

// TODO: Needs checking
@implementation PCEditor (Document)
#import "EditorRulerView.h"
#import "EditorTextView.h"
#import "SyntaxHighlighter.h"
/**
* Checks whether a character is a delimiter.
*
* This function checks whether `character' is a delimiter character,
* (i.e. one of "(", ")", "[", "]", "{", "}") and returns YES if it
* is and NO if it isn't. Additionaly, if `character' is a delimiter,
* `oppositeDelimiter' is set to a string denoting it's opposite
* delimiter and `searchBackwards' is set to YES if the opposite
* delimiter is located before the checked delimiter character, or
* to NO if it is located after the delimiter character.
*/
static inline BOOL CheckDelimiter(unichar character,
unichar * oppositeDelimiter,
BOOL * searchBackwards)
{
if (character == '(')
{
*oppositeDelimiter = ')';
*searchBackwards = NO;
return YES;
}
else if (character == ')')
{
*oppositeDelimiter = '(';
*searchBackwards = YES;
return YES;
}
else if (character == '[')
{
*oppositeDelimiter = ']';
*searchBackwards = NO;
return YES;
}
else if (character == ']')
{
*oppositeDelimiter = '[';
*searchBackwards = YES;
return YES;
}
else if (character == '{')
{
*oppositeDelimiter = '}';
*searchBackwards = NO;
return YES;
}
else if (character == '}')
{
*oppositeDelimiter = '{';
*searchBackwards = YES;
return YES;
}
else
{
return NO;
}
}
/**
* Attempts to find a delimiter in a certain string around a certain location.
*
* Attempts to locate `delimiter' in `string', starting at
* location `startLocation' a searching forwards (backwards if
* searchBackwards = YES) at most 1000 characters. The argument
* `oppositeDelimiter' denotes what is considered to be the opposite
* delimiter of the one being search for, so that nested delimiters
* are ignored correctly.
*
* @return The location of the delimiter if it is found, or NSNotFound
* if it isn't.
*/
unsigned int FindDelimiterInString(NSString * string,
unichar delimiter,
unichar oppositeDelimiter,
unsigned int startLocation,
BOOL searchBackwards)
{
unsigned int i;
unsigned int length;
unichar (*charAtIndex)(id, SEL, unsigned int);
SEL sel = @selector(characterAtIndex:);
int nesting = 1;
charAtIndex = (unichar (*)(id, SEL, unsigned int)) [string
methodForSelector: sel];
if (searchBackwards)
{
if (startLocation < 1000)
length = startLocation;
else
length = 1000;
for (i=1; i <= length; i++)
{
unichar c;
c = charAtIndex(string, sel, startLocation - i);
if (c == delimiter)
nesting--;
else if (c == oppositeDelimiter)
nesting++;
if (nesting == 0)
break;
}
if (i > length)
return NSNotFound;
else
return startLocation - i;
}
else
{
if ([string length] < startLocation + 1000)
length = [string length] - startLocation;
else
length = 1000;
for (i=1; i < length; i++)
{
unichar c;
c = charAtIndex(string, sel, startLocation + i);
if (c == delimiter)
nesting--;
else if (c == oppositeDelimiter)
nesting++;
if (nesting == 0)
break;
}
if (i == length)
return NSNotFound;
else
return startLocation + i;
}
}
// --- Parentesis highlighting
- (void)unhighlightCharacter
{
if (isCharacterHighlit)
{
NSTextStorage * textStorage = [textView textStorage];
NSRange r = NSMakeRange(highlitCharacterLocation, 1);
isCharacterHighlit = NO;
[textStorage beginEditing];
// restore the character's color and font attributes
if (previousFont != nil)
{
[textStorage addAttribute: NSFontAttributeName
value: previousFont
range: r];
}
else
{
[textStorage removeAttribute: NSFontAttributeName range: r];
}
if (previousFGColor != nil)
{
[textStorage addAttribute: NSForegroundColorAttributeName
value: previousFGColor
range: r];
}
else
{
[textStorage removeAttribute: NSForegroundColorAttributeName
range: r];
}
if (previousBGColor != nil)
{
[textStorage addAttribute: NSBackgroundColorAttributeName
value: previousBGColor
range: r];
}
else
{
[textStorage removeAttribute: NSBackgroundColorAttributeName
range: r];
}
[textStorage endEditing];
}
}
- (void)highlightCharacterAt:(unsigned int)location
{
if (isCharacterHighlit == NO)
{
NSTextStorage * textStorage = [textView textStorage];
NSRange r = NSMakeRange(location, 1);
NSRange tmp;
highlitCharacterLocation = location;
isCharacterHighlit = YES;
[textStorage beginEditing];
// store the previous character's attributes
ASSIGN(previousFGColor,
[textStorage attribute: NSForegroundColorAttributeName
atIndex: location
effectiveRange: &tmp]);
ASSIGN(previousBGColor,
[textStorage attribute: NSBackgroundColorAttributeName
atIndex: location
effectiveRange: &tmp]);
ASSIGN(previousFont, [textStorage attribute: NSFontAttributeName
atIndex: location
effectiveRange: &tmp]);
[textStorage addAttribute: NSFontAttributeName
value: highlightFont
range: r];
[textStorage addAttribute: NSForegroundColorAttributeName
value: highlightColor
range: r];
[textStorage removeAttribute: NSBackgroundColorAttributeName
range: r];
[textStorage endEditing];
}
}
- (void)computeNewParenthesisNesting
{
NSRange selectedRange;
NSString * myString;
if ([[NSUserDefaults standardUserDefaults] boolForKey: @"DontTrackNesting"])
{
return;
}
selectedRange = [textView selectedRange];
// make sure we un-highlight a previously highlit delimiter
[self unhighlightCharacter];
// if we have a character at the selected location, check
// to see if it is a delimiter character
myString = [textView string];
if (selectedRange.length <= 1 && [myString length] > selectedRange.location)
{
unichar c;
// we must initialize these explicitly in order to make
// gcc shut up about flow control
unichar oppositeDelimiter = 0;
BOOL searchBackwards = NO;
c = [myString characterAtIndex: selectedRange.location];
// if it is, search for the opposite delimiter in a range
// of at most 1000 characters around it in either forward
// or backward direction (depends on the kind of delimiter
// we're searching for).
if (CheckDelimiter(c, &oppositeDelimiter, &searchBackwards))
{
unsigned int result;
result = FindDelimiterInString(myString,
oppositeDelimiter,
c,
selectedRange.location,
searchBackwards);
// and in case a delimiter is found, highlight it
if (result != NSNotFound)
{
[self highlightCharacterAt: result];
}
}
}
}
// --- State
- (void)updateMiniwindowIconToEdited:(BOOL)flag
{
NSImage * icon;
if (flag)
{
icon = [NSImage imageNamed:
[NSString stringWithFormat: @"File_%@_mod", [self fileType]]];
}
else
{
icon = [NSImage imageNamed:
[NSString stringWithFormat: @"File_%@", [self fileType]]];
}
[myWindow setMiniwindowImage: icon];
}
@end