libs-steptalk/Examples/Shell/STShell.m

404 lines
8.7 KiB
Mathematica
Raw Normal View History

/**
STShell
StepTalk Shell
Copyright (c) 2002 Free Software Foundation
Written by: Stefan Urbanek <urbanek@host.sk>
Date: 2002 May 29
This file is part of the StepTalk project.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02111, USA.
*/
#import "STShell.h"
#import <StepTalk/StepTalk.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSNotification.h>
#import <Foundation/NSException.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#include <readline/readline.h>
static Class NSString_class;
static Class NSNumber_class;
NSArray *objcSelectors = nil;
static STShell *sharedShell = nil;
* STEngine.h: Fixed declaration to match implementation to avoid compiler warnings. * STEnvironment.h: Ditto. * STScriptsManager.h: Ditto. * STLanguage.h: Corrected declaration. * STScriptsManager.m: Added needed interface declaration. * GNUmakefile: Added flags to show all warnings except for import. * Module/ObjectiveC/GNUmakefile: Added flags to show all warnings except for import. * Module/Foundation/GNUmakefile: Added flags to show all warnings except for import. * Module/AppKit/AppKitExceptions.m: Used variable to supress compiler warnings. * Module/AppKit/AppKitNotifications.m: Ditto. * Module/AppKit/GNUmakefile: Added flags to show all warnings except for import. * Module/GDL2/GDL2Constants.m: Used variable to supress compiler warnings. * Module/GDL2/GNUmakefile: Added flags to show all warnings except for import. * Module/SimpleTranscripts/GNUmakefile: Added flags to show all warnings except for import. * Module/StepTalk/GNUmakefile: Added flags to show all warnings except for import. * Tools/stalk.m: Added needed interface declaration. * Tools/stupdate_languages.m: Corrected variable declaration and added cast. ApplicationScripting * GNUmakefile: Added flags to be able to compile from the building directories and show all warnings except for import. * NSApplication+additions.m: Added import of needed headers. Added interface declarations to supress compiler warnings. Commented unused variables to supress compiler warnings. Corrected variable types and added necessary casts. * STScriptingSupport.m: Added interface declaraions to supress compiler warnings. Examples/Shell * GNUmakefile: Added flags to show all warnings except for import. * STShell.m: Unified name for private categories. Examples/Server * ChangeLog: Added new file. * GNUmakefile: Added flags to show all warnings except for import. Languages/Smalltalk/ChangeLog * GNUmakefile: Added flags to show all warnings except for import. * STBlock.m: Initialzed variables to supress compiler warnings. * STCompiledMethod.m: Added needed import. * STCompiler.m: Added missing declaration. Wrapped declarations only needed for DEBUG into #ifdefs to supress compiler warnings. Initialzed variables to supress compiler warnings. * STExecutionContext.m: Unified name for private categories. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/steptalk/trunk@16351 72102866-910b-0410-8b05-ffd578937521
2003-04-04 10:57:04 +00:00
@interface STShell(STPrivateMethods)
- (int) completion;
- (NSString *)readLine;
- (void)initReadline;
@end
int complete_handler(void)
{
return [sharedShell completion];
}
@implementation STShell
+ (void)initialize
{
NSString_class = [NSString class];
NSNumber_class = [NSNumber class];
}
+ sharedShell
{
return sharedShell;
}
- initWithEnvironment:(STEnvironment *)env
{
self = [super init];
[self initReadline];
objectStack = [[NSMutableArray alloc] init];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(bundleLoaded:)
name:NSBundleDidLoadNotification
object:nil];
scriptsManager = RETAIN([STScriptsManager defaultManager]);
prompt = @"StepTalk > ";
conversation = [[STConversation alloc] initWithEnvironment:env language:nil];
/* FIXME: make this more clever for completion handler */
if(!sharedShell)
{
sharedShell = self;
}
return self;
}
- (void)updateCompletionList
{
NSMutableArray *array = [[NSMutableArray alloc] init];
RELEASE(completionList);
[array addObjectsFromArray:STAllObjectiveCSelectors()];
completionList = [[NSArray alloc] initWithArray:array];
updateCompletionList = NO;
}
- (void)dealloc
{
RELEASE(objectStack);
RELEASE(completionList);
RELEASE(scriptsManager);
RELEASE(conversation);
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
-(void)bundleLoaded:(NSNotification *)notif
{
updateCompletionList = YES;
}
- (void)initReadline
{
rl_initialize();
rl_bind_key('\t', complete_handler);
}
- (void)setLanguage:(NSString *)langName
{
NSDebugLog(@"Setting language to %@", langName);
[conversation setLanguage:langName];
}
- (void)setEnvironment:(STEnvironment *)newEnv
{
[conversation setEnvironment:newEnv];
}
- (STEnvironment *)environment
{
return [conversation environment];
}
- (void)run
{
STEnvironment *env = [conversation environment];
NSString *line;
id result;
[env setCreatesUnknownObjects:YES];
/* Add standard objects */
[env setObject:self forName:@"Shell"];
[env setObject:self forName:@"Transcript"];
[env setObject:objectStack forName:@"Objects"];
[env setObject:[NSFileManager defaultManager] forName:@"FileManager"];
/* FIXME: This is unsafe !*/
[env setObject:env forName:@"Environment"];
[self showLine:@"Welcome to the StepTalk shell."];
NSLog(@"Environment %@", env);
while(1)
{
line = [self readLine];
if(exitRequest)
break;
if(!line)
continue;
result = [self executeLine:line];
if(result)
{
if(result != objectStack)
{
[objectStack addObject:result];
}
[self showResult:result];
}
else
{
[self showResult:result];
}
}
printf("\n");
}
- (id)executeLine:(NSString *)line
{
STEnvironment *env = [conversation environment];
NSString *cmd;
id result = nil;
/* FIXME: why? */
cmd = [line stringByAppendingString:@" "];
NS_DURING
result = [conversation runScriptFromString:cmd];
NS_HANDLER
[self showException:localException];
NS_ENDHANDLER
[env setObject:line forName:@"LastCommand"];
[env setObject:result forName:@"LastObject"];
return result;
}
- (NSString *)readLine
{
const char *str;
NSString *actualPrompt = prompt;
NSString *line = @"";
BOOL done = NO;
int len;
while(!done)
{
str = readline([actualPrompt cString]);
done = YES;
if(!str)
{
exitRequest = YES;
return nil;
}
len = strlen(str);
if(!len)
return nil;
if(str[len-1] == '\\')
{
actualPrompt = @"... ? ";
str[strlen(str) - 1] = '\0';
done = NO;
}
line = [line stringByAppendingString:[NSString stringWithCString:str]];
}
add_history([line cString]);
return line;
}
- (int)completion
{
STEnvironment *env = [conversation environment];
NSEnumerator *enumerator;
NSMutableSet *set;
NSString *match;
NSString *tail;
NSString *str;
NSArray *array;
int pos = 0;
int c;
if(rl_point <= 0)
{
return 0;
}
pos = rl_point - 1;
c = rl_line_buffer[pos];
while((isalnum(c) || c == '_') && pos >= 0)
{
pos--;
c = rl_line_buffer[pos];
}
pos++;
match = [NSString stringWithCString:rl_line_buffer + pos
length:rl_point - pos];
set = [NSMutableSet set];
if(!completionList || updateCompletionList)
{
[self updateCompletionList];
}
enumerator = [completionList objectEnumerator];
while( (str = [enumerator nextObject]) )
{
if( [str hasPrefix:match] )
{
[set addObject:str];
}
}
enumerator = [[env knownObjectNames] objectEnumerator];
while( (str = [enumerator nextObject]) )
{
if( [str hasPrefix:match] )
{
[set addObject:str];
}
}
array = [set allObjects];
if( [array count] == 0 )
{
printf("\nNo match for completion.\n");
rl_forced_update_display();
}
else if ( [array count] == 1 )
{
str = [array objectAtIndex:0];
str = [str substringFromIndex:rl_point - pos];
rl_insert_text([str cString]);
rl_insert_text(" ");
rl_redisplay();
}
else
{
enumerator = [array objectEnumerator];
tail = [enumerator nextObject];
while( (str = [enumerator nextObject]) )
{
tail = [str commonPrefixWithString:tail options:NSLiteralSearch];
}
tail = [tail substringFromIndex:[match length]];
if( tail && ![tail isEqualToString:@""] )
{
rl_insert_text([tail cString]);
rl_redisplay();
}
else
{
printf("\n");
enumerator = [array objectEnumerator];
while( (str = [enumerator nextObject]) )
{
printf("%s\n", [str cString]);
}
rl_forced_update_display();
}
}
return 0;
}
- (void)exit
{
/* FIXME: this is not nice */
exit(0);
}
- (id)executeScriptNamed:(NSString *)scriptName
{
STScript *script = [scriptsManager scriptWithName:scriptName];
id result = nil;
if(!script)
{
[self showError:[NSString stringWithFormat:
@"Unable to find script with name '%@'",
scriptName]];
}
else
{
NS_DURING
result = [conversation runScriptFromString:[script source]];
NS_HANDLER
[self showException:localException];
NS_ENDHANDLER
}
return result;
}
- (void)setPrompt:(NSString *)aString
{
ASSIGN(prompt, aString);
}
- (NSString *)prompt
{
return prompt;
}
@end