fixed some warnings
[TestXSLT.git] / XMLTextView.m
index 55af190..fb78013 100644 (file)
 @implementation XMLTextView
 
 
-- (id)init {
 
-       if (self = [super init]) {
-               [self setRichText:NO];
-       }
-
-       return self;
+-(void)awakeFromNib {
 
+       [self setRichText:NO];
+       resultstack = NULL;
+       defaults = [NSUserDefaults standardUserDefaults];
+       
+       // register our two input text views to receive file drags
+       //
+ //    [xmlView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
+ //    [xsltView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
+       
+       NSFont *computerFont = [NSFont fontWithName:@"Courier" size:12.0];
+       [self setFont:computerFont];
+       
+       [self setAllowsUndo:YES];
+       
 }
 
 
+- (void)dealloc {
+       
+       if (resultstack)
+               free(resultstack);
+       [errorString release];
+}
 
 -(void)selectLineByNumber:(int)line {
 
 
 
 
--(void)pasteAsRichText:(id)sender {
-
-
-       NSLog(@"paste as rich text");
-       //      [self pasteAsPlainText:sender];
-
-}
-
-
 
 
 - (void)keyDown:(NSEvent *)event {
 
        NSRange selectedRange;
        
+       if (![defaults boolForKey:@"enableSyntaxAnalysis"]) {
+               [super keyDown:event];
+               return;
+       }
+       
        if ([[event characters] isEqual:@"\033"]) {
 
                if ([event modifierFlags] || [event isARepeat]) {
                }
        }
 
+       
+       /*
+       if ([event modifierFlags] & NSFunctionKeyMask) {
+               [self didChangeText];
+       }
+       */
+       
+       //NSFunctionKeyMask
+       
+       
        [super keyDown:event];
 
 }
 
 - (BOOL)completeAfterSlash {
 
-       NSRange selectedRange = [self selectedRange], tagNameRange;
-       NSString *tagName = nil;
-
-       tagNameRange = [self scanBackwardsForOpeningTagNameInRange:NSMakeRange(0, selectedRange.location - 1)];
-
-       if (tagNameRange.location == NSNotFound) {
+       int location = [self selectedRange].location - 1;
+       
+       [self calculateTagStackAtLocation:location];
+       
+       if (stackresult) {
                return NO;
        }
 
-       tagName = [[self string] substringWithRange:tagNameRange];
-       
-//     NSLog(@"completion!");
+       NSTextStorage *storage = [self textStorage];
+       [storage beginEditing];
+       [storage deleteCharactersInRange:NSMakeRange(location, 1)];
+       [storage endEditing];
 
-       if (tagName == nil) {
-               return NO;
-       }
+       [self setSelectedRange:NSMakeRange(location, 0)];
 
-       [self insertText:[NSString stringWithFormat:@"/%@>", tagName]];
+       [self complete:nil];
 
-       [self flashRange:tagNameRange];
-               
+       
        return YES;
 }
 
 
+
 - (void)flashRange:(NSRange)range {
 
        NSRect tagNameRect;
        
 }
 
+-(NSString *)calculateTagStack {
 
+       return [self calculateTagStackAtLocation:[self selectedRange].location];
+       
+}
 
-- (void)complete:(id)sender {
-
-       NSRange selectedRange, leftRange, rightRange, tagNameRange;
-       NSString *tagName = nil;
-       NSString *data = nil;
-       int location;
+-(BOOL)checkWellFormed {
 
-       data = [self string];
+       int result;
+       NSData *data = [XMLUtils getDataWithEncodingFromString:[self string]];
 
-       selectedRange = [self selectedRange];
-       location = selectedRange.location;
+       parser = XML_ParserCreate(NULL);
 
-       /* May not have a selection, and insertion point must be preceded by at
-               * least one tag, which means at least 3 characters must be to its left
-               */
-       if (selectedRange.length > 0 || location < 3) {
-               NSBeep();
-               return;
+       if (!parser) {
+               NSLog(@"Unable to allocate expat parser in XMLTextView:checkWellFormed!");
+               return NO;
        }
 
-       /* leftRange is everything from beginning of data to the insertion point.
-               * rightRange is everything after the insertion point to the end of the data
-               */
-       leftRange  = NSMakeRange(0, location);
-       rightRange = NSMakeRange(location, [data length] - leftRange.length);
-
+       result = XML_Parse(parser, [data bytes], [data length], 1);
 
-
-       tagNameRange = [self scanBackwardsForOpeningTagNameInRange:leftRange];
-
-       if (tagNameRange.location == NSNotFound) {
-               NSBeep();
-               return;
+       if (!result) {
+               [self setError:[NSString stringWithFormat:@"%s, line %d, column %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser), XML_GetCurrentColumnNumber(parser)] atLine:XML_GetCurrentLineNumber(parser) atColumn:XML_GetCurrentColumnNumber(parser)];
+       } else if (error) {
+               [self clearError];
        }
-
-       tagName = [data substringWithRange:tagNameRange];
        
-       [self insertText:[NSString stringWithFormat:@"</%@>", tagName]];
-       [self setSelectedRange:selectedRange];
-
-       [self flashRange:tagNameRange];
+       XML_ParserFree(parser);
        
+       return result > 0;
 }
 
 
 
--(NSRange)scanBackwardsForOpeningTagNameInRange:(NSRange)scanRange {
-
-       NSRange tagNameEndRange, tagContentPlusEndRange, leftAngleRange, openingTagRange, slashRange;
-       NSCharacterSet *angleSet = [NSCharacterSet characterSetWithCharactersInString:@"<>"];
-       NSCharacterSet *tagNameDelimiterSet = [NSCharacterSet characterSetWithCharactersInString:@" <>"];
-       NSString *tagName = nil;
-       NSString *data = [self string];
-       NSString *character;
-       NSRange tagNameRange;
-
+-(void)clearError {
        
-       /* find the first occurence of angle brackets, both opening or closing,
-       * in the range to the left of the insertion point, searching backwards
-       * from the insertion point
-       */
-       leftAngleRange = [data rangeOfCharacterFromSet:angleSet options:NSBackwardsSearch range:scanRange];
+       errorLine = errorColumn = 0;
+       error = NO;
+       [errorString release];
+       errorString = @"";
+       
+}
 
-       /* abort unless we found something */
-       if (leftAngleRange.location == NSNotFound) {
-               return NSMakeRange(NSNotFound, 0);
-       }
+-(BOOL)hasError {
+       
+       return error;
+       
+}
+-(void)setError:(NSString *)errstring atLine:(int)line atColumn:(int)column {
+       
+       errorLine = line;
+       errorColumn = column;
+       error = YES;
+       [errstring retain];
+       [errorString release];
+       errorString = errstring;
+       
+}
 
-       //      NSLog(@"leftbracket: %d %d", leftAngleRange.location, leftAngleRange.length);
 
 
-       /* We expect the nearest angle bracket to our left to be a closing one, we will
-               * not try to complete an open tag if we find an opening bracket instead.
-               */
-       character = [data substringWithRange:leftAngleRange];
-       if (![character isEqual:@">"]) {
-               return NSMakeRange(NSNotFound, 0);
-       }
 
-       /* shift end of scanRange so it ends after the closing angle bracket we just found */
-       scanRange = NSMakeRange(0, leftAngleRange.location);
 
 
-       /* Now search again from the end of that range backward to the beginning of the data
-               * and look for another angle bracket.
-               */
-       leftAngleRange = [data rangeOfCharacterFromSet:angleSet options:NSBackwardsSearch range:NSMakeRange(0, scanRange.length - 1)];
 
-       /* again abort unless we found something */
-       if (leftAngleRange.location == NSNotFound) {
-               return NSMakeRange(NSNotFound, 0);
-       }
+-(NSString *)calculateTagStackAtLocation:(int)location {
 
-       //NSLog(@"leftbracket: %d %d", leftAngleRange.location, leftAngleRange.length);
+       const char *buffer;
+       int i;
+       NSRange selectedRange;
+       NSMutableString *mystack;
 
-       /* This time we expect to see an opening angle bracket */
-       character = [data substringWithRange:leftAngleRange];
-       if (![character isEqual:@"<"]) {
-               return NSMakeRange(NSNotFound, 0);
+       if (![[NSUserDefaults standardUserDefaults] boolForKey:@"enableSyntaxAnalysis"]) {
+               return @"";
        }
+       
+       buffer = [[self string] lossyCString];
+       selectedRange = [self selectedRange];
+       
+       if (resultstack)
+               free(resultstack);
 
+       stackresult = 0;
+       resultstack = findCompletion(buffer, strlen(buffer), location, &stackresult, tagpositions);
 
-       /* This will indicate the range of the entire nearest tag to our left,
-               * we assume that's the opening tag */
-       openingTagRange = NSMakeRange(leftAngleRange.location, (scanRange.length - leftAngleRange.location) + 1);
+       mystack = [NSMutableString stringWithCapacity:1000];
+       
+       for (i = 0; resultstack && *(resultstack[i]); i++) {
+               if (*(resultstack[i+1])) {
+                       [mystack appendFormat:@"%s/", resultstack[i]];
+               } else {
+                       if (stackresult) {
+                               [mystack appendFormat:@"%s", resultstack[i]];
+                       } else {
+                               [mystack appendFormat:@"<%s>", resultstack[i]];
+                       }
+                       
+                       
+               }
 
-       /* check if it is indeed an opening tag, i.e. no slash after the opening bracket */
-       slashRange = NSMakeRange(openingTagRange.location + 1, 1);
-       character = [data substringWithRange:slashRange];
-       if ([character isEqual:@"/"]) {
-               return NSMakeRange(NSNotFound, 0);
        }
 
-       /* Don't complete processing instructions, comments etc. */
-       if ([character isEqual:@"?"] || [character isEqual:@"!"]) {
-               return NSMakeRange(NSNotFound, 0);
+
+       switch (stackresult) {
+       
+               case 1:
+                       [mystack appendString:@" (In tag)"];
+                       break;
+
+               case 3:
+                       [mystack appendString:@" (In comment section)"];
+                       break;
+               case 5:
+                       [mystack appendString:@" (In CDATA section)"];
+                       break;
+                       
+               case 8:
+                       [mystack appendString:@" (No open tags)"];
+                       break;
+                       
+               case 16:
+                       [mystack appendString:@" (Tags are balanced)"];
+                       break;
        }
        
        
-       /* check if it is a merged start and end tag, i.e. slash before closing bracket */
-       slashRange = NSMakeRange((openingTagRange.location + openingTagRange.length) - 2, 1);
-       character = [data substringWithRange:slashRange];
-       if ([character isEqual:@"/"]) {
-               return NSMakeRange(NSNotFound, 0);
-       }
-
-
-       tagContentPlusEndRange = NSMakeRange(openingTagRange.location + 1, openingTagRange.length - 1);
-
-       //NSLog(@"tagcontent: %d %d", tagContentPlusEndRange.location, tagContentPlusEndRange.length);
+       return mystack;
+       
+}
 
-       tagNameEndRange = [data rangeOfCharacterFromSet:tagNameDelimiterSet options:0 range:tagContentPlusEndRange];
+- (void)complete:(id)sender {
 
+       NSRange selectedRange, tagNameRange;
+       NSString *tagName = nil;
+       int location, i;
 
-       tagNameRange = NSMakeRange(tagContentPlusEndRange.location, tagNameEndRange.location - tagContentPlusEndRange.location);
+//     data = [self string];
 
-       tagName = [data substringWithRange:tagNameRange];
+       selectedRange = [self selectedRange];
+       location = selectedRange.location;
 
-       if ([tagName length] < 1) {
-               return NSMakeRange(NSNotFound, 0);
+       /* May not have a selection, and insertion point must be preceded by at
+               * least one tag, which means at least 3 characters must be to its left
+               */
+       if (selectedRange.length > 0 || location < 3 || stackresult) {
+               NSBeep();
+               return;
        }
 
 
-       return tagNameRange;
-       
-       //NSLog(@"tagrange: %d %d / %@", tagNameEndRange.location, tagNameEndRange.length, tagName);
-
+       for (i = 0; resultstack && *(resultstack[i]); i++) {
+               if (!*(resultstack[i+1])) {
+                       tagName = [NSString stringWithCString:resultstack[i]];
+                       tagNameRange = NSMakeRange(tagpositions[i*2], tagpositions[i*2+1]- tagpositions[i*2]);
+               }
+       }
        
 
+       [self insertText:[NSString stringWithFormat:@"</%@>", tagName]];
+       [self setSelectedRange:selectedRange];
 
-
-
-
+       [self flashRange:tagNameRange];
+       [self calculateTagStack];
+       
 }
 
 
 
 
+
 @end