Skip to content

Commit

Permalink
• speed ups for console's text storage esp. for outputting stuff
Browse files Browse the repository at this point in the history
• fixed bug for functionHint in RConsole after invoking edit/fix()
• set consoleTextView to allow non-contiguous layouting for speed

git-svn-id: https://svn.r-project.org/R-packages/trunk/Mac-GUI@6041 694ef91d-65df-0310-b7bb-92e67a308ead
  • Loading branch information
Hans-Jörg Bibiko committed Jan 25, 2012
1 parent 6bc2706 commit df52f01
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 16 deletions.
3 changes: 3 additions & 0 deletions RConsoleTextStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@

@interface RConsoleTextStorage : NSTextStorage {
NSMutableAttributedString* cont;
NSFont* theFont;
NSColor* lastUsedColor;
}

- (void) insertText: (NSString*) text atIndex: (int) index withColor: (NSColor*) color;
- (void)setFont:(NSFont*)aFont;

@end
22 changes: 20 additions & 2 deletions RConsoleTextStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,17 @@ - (id) init
self = [super init];
if (self) {
cont = [[NSMutableAttributedString alloc] init];
theFont = [[[RController sharedController] currentFont] retain];
lastUsedColor = nil;
}
return self;
}

- (void) dealloc
{
[cont release];
[theFont release];
if(lastUsedColor) [lastUsedColor release];
[super dealloc];
}

Expand Down Expand Up @@ -82,9 +86,23 @@ - (void) insertText: (NSString*) text atIndex: (int) index withColor: (NSColor*)
{
//NSLog(@"insert %d chars at %d to result in %d length", [text length], index, [cont length]+[text length]);
[cont replaceCharactersInRange: NSMakeRange(index,0) withString: text];
[cont addAttribute:@"NSColor" value:color range: NSMakeRange(index, [text length])];
[cont addAttribute:@"NSFont" value:[[RController sharedController] currentFont] range: NSMakeRange(index, [text length])];
// cont will use the current attributes at cursor location, change them only if color or font were changed
if(!lastUsedColor || lastUsedColor != color) {
if(lastUsedColor) [lastUsedColor release];
lastUsedColor = [color retain];
[cont addAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
theFont, NSFontAttributeName,
color, NSForegroundColorAttributeName,
nil] range:NSMakeRange(index, [text length])];
}
[self edited:NSTextStorageEditedCharacters|NSTextStorageEditedAttributes range: NSMakeRange(index,0) changeInLength:[text length]];
}

- (void)setFont:(NSFont*)aFont
{
if(theFont) [theFont release], theFont = nil;
theFont = [aFont retain];
if(lastUsedColor) [lastUsedColor release], lastUsedColor = nil;
}

@end
31 changes: 24 additions & 7 deletions RController.m
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@

static RController* sharedRController;

static inline const char* NSStringUTF8String(NSString* self)
{
typedef const char* (*SPUTF8StringMethodPtr)(NSString*, SEL);
static SPUTF8StringMethodPtr SPNSStringGetUTF8String;
if (!SPNSStringGetUTF8String) SPNSStringGetUTF8String = (SPUTF8StringMethodPtr)[NSString instanceMethodForSelector:@selector(UTF8String)];
const char* to_return = SPNSStringGetUTF8String(self, @selector(UTF8String));
return to_return;
}

@interface R_WebViewSearchWindow : NSWindow
@end

Expand Down Expand Up @@ -300,6 +309,7 @@ - (void) awakeFromNib {
char *args[5]={ "R", "--no-save", "--no-restore-data", "--gui=cocoa", 0 };
SLog(@"RController.awakeFromNib");

[consoleTextView setConsoleMode: YES];
[consoleTextView setEditable:YES];
[consoleTextView setFont:[Preferences unarchivedObjectForKey:RConsoleDefaultFont withDefault:[NSFont fontWithName:@"Monaco" size:11]]];

Expand All @@ -316,8 +326,10 @@ - (void) awakeFromNib {
forEventClass:kCoreEventClass
andEventID:kAEOpenDocuments];

[consoleTextView setConsoleMode: YES];
NSLayoutManager *lm = [[consoleTextView layoutManager] retain];
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
[lm setAllowsNonContiguousLayout:YES];
#endif
NSTextStorage *origTS = [[consoleTextView textStorage] retain];
textStorage = [[RConsoleTextStorage alloc] init];
[origTS removeLayoutManager:lm];
Expand Down Expand Up @@ -902,8 +914,9 @@ - (void) fontSizeChangedBy:(float)delta withSender:(id)sender
[[NSUserDefaults standardUserDefaults] setObject:[NSArchiver archivedDataWithRootObject:font] forKey:RConsoleDefaultFont];
[consoleTextView setFont:font];
// Force to scroll view to cursor
[consoleTextView insertText:@""];
[consoleTextView scrollRangeToVisible:[consoleTextView selectedRange]];
}
[[consoleTextView textStorage] setFont:font];
[self setOptionWidth:YES];
}
// Change size in R script windows
Expand Down Expand Up @@ -1079,8 +1092,10 @@ - (void) handleFlushConsole {

/* this writes R output to the Console window, but indirectly by using a buffer */
- (void) handleWriteConsole: (NSString*) txt withType: (int) oType {

if (!txt) return;
const char *s = [txt UTF8String];

const char *s = NSStringUTF8String(txt);
// NSLog(@"handleWriteConsole[%d(%d,%d)] %@", oType, writeBufferType, writeBufferPos - writeBuffer, txt);
int sl = strlen(s);
int fits = writeBufferLen - (writeBufferPos - writeBuffer) - 1;
Expand All @@ -1090,19 +1105,20 @@ - (void) handleWriteConsole: (NSString*) txt withType: (int) oType {
if (writeBuffer != writeBufferPos && (writeBufferType != oType || (fits < sl && fits > writeBufferHighWaterMark))) {
// for efficiency we're not using handleFlushConsole, because that would trigger stdxx flush, too
[self writeConsoleDirectly:[NSString stringWithUTF8String:writeBuffer]
withColor:[consoleColors objectAtIndex:writeBufferType ? iErrorColor : iOutputColor]];
withColor:(NSColor*)CFArrayGetValueAtIndex((CFArrayRef)consoleColors, writeBufferType ? iErrorColor : iOutputColor)];
writeBufferPos = writeBuffer;
fits = writeBufferLen - 1;
}

writeBufferType = oType;
NSColor *writingColor = (NSColor*)CFArrayGetValueAtIndex((CFArrayRef)consoleColors, writeBufferType ? iErrorColor : iOutputColor);

// this seems a bit insane given that we could just pass the string as a whole, but it should be exteremely rare
// since we are dealing with small strings most of the time
while (fits < sl) { // ok, we're in a situation where we must split the string
memcpy(writeBufferPos, s, fits);
writeBufferPos[writeBufferLen - 1] = 0;
[self writeConsoleDirectly:[NSString stringWithUTF8String:writeBuffer] withColor:[consoleColors objectAtIndex:writeBufferType ? iErrorColor : iOutputColor]];
[self writeConsoleDirectly:[NSString stringWithUTF8String:writeBuffer] withColor:writingColor];
sl -= fits; s += fits;
writeBufferPos = writeBuffer;
fits = writeBufferLen - 1;
Expand All @@ -1113,7 +1129,7 @@ - (void) handleWriteConsole: (NSString*) txt withType: (int) oType {

// flush the buffer if the low watermark is reached
if (fits - sl < writeBufferLowWaterMark) {
[self writeConsoleDirectly:[NSString stringWithUTF8String:writeBuffer] withColor:[consoleColors objectAtIndex:writeBufferType ? iErrorColor : iOutputColor]];
[self writeConsoleDirectly:[NSString stringWithUTF8String:writeBuffer] withColor:writingColor];
writeBufferPos = writeBuffer;
}
}
Expand Down Expand Up @@ -1286,8 +1302,9 @@ - (void)handleWritePrompt: (NSString*) prompt {
if (promptLength>0) {
[textStorage insertText:prompt atIndex: textLength withColor:[consoleColors objectAtIndex:iPromptColor]];
if (promptLength>1) // this is a trick to make sure that the insertion color doesn't change at the prompt
[textStorage addAttribute:@"NSColor" value:[consoleColors objectAtIndex:iInputColor] range:NSMakeRange(promptPosition+promptLength-1, 1)];
[textStorage insertText:@"" atIndex:promptPosition+promptLength withColor:[consoleColors objectAtIndex:iInputColor]];
committedLength=promptPosition+promptLength;

}
committedLength=promptPosition+promptLength;
lastCommittedLength = committedLength;
Expand Down
17 changes: 10 additions & 7 deletions RTextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ - (void)keyDown:(NSEvent *)theEvent

// Check if something is selected and wrap it into matching pair characters and preserve the selection
// - in RConsole only if selection is in the last line
if((([self isRConsole] && [[self string] lineRangeForRange:NSMakeRange([[self string] length]-1,0)].location+1 < r.location) || ![self isRConsole])
if((([self isRConsole] & ([[self string] lineRangeForRange:NSMakeRange([[self string] length]-1,0)].location+1 < r.location) || ![self isRConsole]))
&& [self wrapSelectionWithPrefix:[NSString stringWithFormat:@"%c", ck] suffix:complement]) {
SLog(@"RTextView: selection was wrapped with auto-pairs");
return;
Expand Down Expand Up @@ -848,10 +848,13 @@ - (NSString*)functionNameForCurrentScope

SLog(@" - invalid current word -> start parsing for current function scope");

// if we're in the RConsole do parse the current line only
if([self isRConsole] && ([[self delegate] lastCommittedLength] <= selectedRange.location))
// if we're in the RConsole don't parse beyond committedLength
// we have to check class since it runs in its own thread (but not sure - if one uses
// [self isRConsole] it doesn't work)
if([[self delegate] isKindOfClass:[RController class]] & ([[RController sharedController] lastCommittedLength] <= selectedRange.location)) {
parseRange = NSMakeRange([[self delegate] lastCommittedLength],
[parseString length]-[[self delegate] lastCommittedLength]);
}

// sanety check; if it fails bail
if(selectedRange.location - parseRange.location <= 0) {
Expand Down Expand Up @@ -950,7 +953,7 @@ - (IBAction)makeASCIIconform:(id)sender
return;

// for Rconsole only allow non-committed strings
if([(RTextView*)self isRConsole] && ([[RController sharedController] lastCommittedLength] > replaceRange.location)) {
if([self isRConsole] & ([[RController sharedController] lastCommittedLength] > replaceRange.location)) {
NSUInteger cl = [[RController sharedController] lastCommittedLength];
if(NSMaxRange(replaceRange) < cl) {
NSBeep();
Expand Down Expand Up @@ -995,8 +998,8 @@ - (IBAction)unescapeUnicode:(id)sender
return;

// for Rconsole only allow non-committed strings
if([(RTextView*)self isRConsole] && ([[self delegate] lastCommittedLength] > replaceRange.location)) {
NSUInteger cl = [[self delegate] lastCommittedLength];
if([self isRConsole] & ([[RController sharedController] lastCommittedLength] > replaceRange.location)) {
NSUInteger cl = [[RController sharedController] lastCommittedLength];
if(NSMaxRange(replaceRange) < cl) {
NSBeep();
return;
Expand Down Expand Up @@ -1049,7 +1052,7 @@ - (void)changeFont:(id)sender
if(!font) return;

// If user selected something change the selection's font only
if(![self isRConsole] && ([[[[self window] windowController] document] isRTF] || [self selectedRange].length)) {
if(![self isRConsole] & ([[[[self window] windowController] document] isRTF] || [self selectedRange].length)) {
// register font change for undo
NSRange r = [self selectedRange];
[self shouldChangeTextInRange:r replacementString:[[self string] substringWithRange:r]];
Expand Down

0 comments on commit df52f01

Please sign in to comment.