├── .gitattributes ├── .gitignore ├── markdown.icns ├── English.lproj ├── InfoPlist.strings ├── Credits.rtf ├── MyDocument.xib └── MainMenu.xib ├── Inconsolata.otf ├── MarkEdit_Prefix.pch ├── main.m ├── MarkdownDocument.h ├── MarkdownDelegate.h ├── README.md ├── markdown_reference.md ├── MarkEdit-Info.plist ├── MarkdownDocument.m ├── MarkEdit.xcodeproj └── project.pbxproj └── MarkdownDelegate.m /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -crlf -diff -merge 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | *.pbxuser 4 | *.perspectivev3 5 | -------------------------------------------------------------------------------- /markdown.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bodhi/MarkdownEditor/HEAD/markdown.icns -------------------------------------------------------------------------------- /English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Inconsolata.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bodhi/MarkdownEditor/HEAD/Inconsolata.otf -------------------------------------------------------------------------------- /MarkEdit_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'MarkEdit' target in the 'MarkEdit' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MarkEdit 4 | // 5 | // Created by bodhi on 31/03/10. 6 | // Copyright 2010 Apple Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **) argv); 14 | } 15 | -------------------------------------------------------------------------------- /MarkdownDocument.h: -------------------------------------------------------------------------------- 1 | // 2 | // MyDocument.h 3 | // MarkEdit 4 | // 5 | // Created by bodhi on 31/03/10. 6 | // Copyright 2010 Apple Inc. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | #import "MarkdownDelegate.h" 12 | 13 | @interface MarkdownDocument : NSDocument 14 | { 15 | IBOutlet NSTextView *textView; 16 | 17 | NSMutableAttributedString *string; 18 | 19 | IBOutlet MarkdownDelegate *mdDelegate; 20 | 21 | NSRange originalRange; 22 | } 23 | 24 | @property(retain) NSMutableAttributedString *string; 25 | @end 26 | -------------------------------------------------------------------------------- /English.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1138 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \viewkind0 5 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 6 | 7 | \f0\fs24 \cf0 Written by Bodhi Philpot\ 8 | \ 9 | {\field{\*\fldinst{HYPERLINK "http://keshiki.net/markdown-editor"}}{\fldrslt http://keshiki.net/markdown-editor}}\ 10 | {\field{\*\fldinst{HYPERLINK "http://markdown@keshiki.net"}}{\fldrslt markdown@keshiki.net}}\ 11 | \ 12 | Uses the fantastic OgreKit:\ 13 | English Page: {\field{\*\fldinst{HYPERLINK "http://web.me.com/oasis/ogrekit/About_%28English%29.html"}}{\fldrslt http://web.me.com/oasis/ogrekit/About_%28English%29.html}}\ 14 | Japanese Page: {\field{\*\fldinst{HYPERLINK "http://web.me.com/oasis/ogrekit/About.html"}}{\fldrslt http://web.me.com/oasis/ogrekit/About.html}}\ 15 | \ 16 | Icon courtesy of Olivier Refalo\ 17 | {\field{\*\fldinst{HYPERLINK "https://github.com/orefalo"}}{\fldrslt https://github.com/orefalo}}} -------------------------------------------------------------------------------- /MarkdownDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // MarkdownDelegate.h 3 | // MarkEdit 4 | // 5 | // Created by bodhi on 1/04/10. 6 | // Copyright 2010 Apple Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class OGRegularExpression; 12 | 13 | @interface MarkdownDelegate : NSObject { 14 | NSTextView *text; 15 | 16 | NSDictionary *blockquoteAttributes, *metaAttributes, 17 | *codeAttributes, *strongAttributes, *emAttributes, 18 | *h1Attributes, *h2Attributes, *defaultAttributes, 19 | *hrAttributes; 20 | 21 | NSMutableDictionary *references; 22 | 23 | NSString *MarkdownCodeSection; 24 | 25 | OGRegularExpression *imageNoAttachment; 26 | OGRegularExpression *attachedImage; 27 | OGRegularExpression *attachmentNoImage; 28 | 29 | OGRegularExpression *inlinePattern, *linkRegex, *image, *setex, *blank, *indented, *bareLink, *hrRegexp; 30 | 31 | NSArray *mainOrder, *lineBlocks; 32 | 33 | NSDictionary *blocks; 34 | 35 | bool newReferences; 36 | 37 | int baseFontSize; 38 | 39 | NSString *attachmentChar; 40 | NSURL *baseURL; 41 | 42 | NSMutableParagraphStyle *defaultStyle; 43 | } 44 | 45 | @property (assign) IBOutlet NSTextView *text; 46 | @property (retain) NSString *attachmentChar; 47 | @property (retain) NSURL *baseURL; 48 | - (void)markupString:(NSMutableAttributedString *)string; 49 | -(void)makeTextLarger:(NSMutableAttributedString *)string; 50 | -(void)makeTextSmaller:(NSMutableAttributedString *)string; 51 | -(void)resetTextSize:(NSMutableAttributedString *)string; 52 | -(void)setWidth:(CGFloat)width; 53 | 54 | -(NSRange)visibleRange; 55 | -(void)recenterOn:(NSRange)range; 56 | @end 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Markdown Editor 2 | ==== 3 | 4 | See for a more detailed 5 | description. 6 | 7 | To Build: you need to get a copy of OgreKit. I'm using v2.1.4 from 8 | . Eventually I'll 9 | include it in the repository, but not yet. 10 | 11 | OgreKit needs to be in the same directory as the project folder (NOT 12 | the project itself), so if `MarkEdit.xcodeproj` is in 13 | `/Users/bodhi/Code/MarkEdit`, then OgreKit should be in 14 | `/Users/bodhi/Code/OgreKit_2_1_4`. If you have it somewhere else, you'll need 15 | to delete the reference to OgreKit in the Xcode project, and re-add 16 | it. Then, you have to drag the OgreKit.framework (probably first one 17 | in the project list, there are 2) to the "Copy Files" phase of the 18 | MarkEdit application target. 19 | 20 | Things to work on 21 | ---- 22 | 23 | * An automated tests suite 24 | * Editing around inline images was very buggy, but it seems I've ironed out most of the bugs with it. 25 | * Strong spans `**` nested in emphasis spans `*` aren't picked up 26 | * Implicitly nested lists aren't highlighted correctly 27 | * Lists with multiple paragraphs aren't always picked up properly 28 | * Automatic indentation doesn't work well on hard-wrapped paragraphs 29 | * The cursor sometimes gets drawn in the wrong place when deleting text. I think this has something to do with me making the wrong sequence of calls to manage the NSTextView system. 30 | * Making the code easier to understand. 31 | 32 | --- 33 | 34 | Thanks for your interest in this project! To contact me, send me a message on GitHub, [on Twitter](http://twitter.com/bodhi) or [send me an email](mailto:markdown@keshiki.net) -------------------------------------------------------------------------------- /markdown_reference.md: -------------------------------------------------------------------------------- 1 | # Syntax Cheatsheet 2 | 3 | ## Phrase Emphasis 4 | 5 | *italic* **bold** 6 | _italic_ __bold__ 7 | 8 | ## Links 9 | 10 | Inline: 11 | An [example](http://url.com/ "Title") 12 | 13 | Reference-style labels (titles are optional): 14 | An [example][id]. Then, anywhere 15 | else in the doc, define the link: 16 | 17 | [id]: http://example.com/ "Title" 18 | 19 | ## Images 20 | 21 | Inline (titles are optional): 22 | ![alt text](/path/img.jpg "Title") 23 | 24 | Reference-style: 25 | ![alt text][id] 26 | 27 | [id]: /url/to/img.jpg "Title" 28 | 29 | ## Headers 30 | 31 | Setext-style: 32 | Header 1 33 | ======== 34 | 35 | Header 2 36 | -------- 37 | 38 | atx-style (closing #'s are optional): 39 | # Header 1 # 40 | 41 | ## Header 2 ## 42 | 43 | ###### Header 6 44 | 45 | ## Lists 46 | 47 | Ordered, without paragraphs: 48 | 1. Foo 49 | 2. Bar 50 | 51 | Unordered, with paragraphs: 52 | * A list item. 53 | 54 | With multiple paragraphs. 55 | 56 | * Bar 57 | 58 | You can nest them: 59 | * Abacus 60 | * answer 61 | * Bubbles 62 | 1. bunk 63 | 2. bupkis 64 | * BELITTLER 65 | 3. burper 66 | * Cunning 67 | 68 | ## Blockquotes 69 | 70 | > Email-style angle brackets 71 | > are used for blockquotes. 72 | 73 | > > And, they can be nested. 74 | 75 | > #### Headers in blockquotes 76 | > 77 | > * You can quote a list. 78 | > * Etc. 79 | 80 | ## Code Spans 81 | 82 | `` spans are delimited 83 | by backticks. 84 | 85 | You can include literal backticks like `` `this` ``. 86 | 87 | ## Preformatted Code Blocks 88 | 89 | Indent every line of a code block by at least 4 spaces or 1 tab. 90 | This is a normal paragraph. 91 | 92 | This is a preformatted 93 | code block. 94 | 95 | ## Horizontal Rules 96 | 97 | Three or more dashes or asterisks: 98 | 99 | --- 100 | 101 | * * * 102 | 103 | - - - - 104 | ## Manual Line Breaks 105 | 106 | End a line with two or more spaces: 107 | Roses are red, 108 | Violets are blue. -------------------------------------------------------------------------------- /MarkEdit-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ATSApplicationFontsPath 6 | Fonts 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleDocumentTypes 10 | 11 | 12 | CFBundleTypeName 13 | Text Files 14 | CFBundleTypeRole 15 | Editor 16 | LSItemContentTypes 17 | 18 | public.plain-text 19 | 20 | LSTypeIsPackage 21 | 22 | NSDocumentClass 23 | MarkdownDocument 24 | NSPersistentStoreTypeKey 25 | Binary 26 | 27 | 28 | CFBundleTypeName 29 | Data 30 | CFBundleTypeRole 31 | Editor 32 | LSItemContentTypes 33 | 34 | public.data 35 | 36 | LSTypeIsPackage 37 | 38 | NSDocumentClass 39 | MarkdownDocument 40 | NSPersistentStoreTypeKey 41 | Binary 42 | 43 | 44 | CFBundleExecutable 45 | ${EXECUTABLE_NAME} 46 | CFBundleIconFile 47 | markdown.icns 48 | CFBundleIdentifier 49 | net.keshiki.${PRODUCT_NAME:rfc1034identifier} 50 | CFBundleInfoDictionaryVersion 51 | 6.0 52 | CFBundleName 53 | ${PRODUCT_NAME} 54 | CFBundlePackageType 55 | APPL 56 | CFBundleShortVersionString 57 | 0.2.1 58 | CFBundleSignature 59 | mded 60 | CFBundleURLTypes 61 | 62 | CFBundleVersion 63 | 0.2.1 64 | LSApplicationCategoryType 65 | public.app-category.utilities 66 | LSMinimumSystemVersion 67 | ${MACOSX_DEPLOYMENT_TARGET} 68 | NSMainNibFile 69 | MainMenu 70 | NSPrincipalClass 71 | NSApplication 72 | NSServices 73 | 74 | UTExportedTypeDeclarations 75 | 76 | UTImportedTypeDeclarations 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /MarkdownDocument.m: -------------------------------------------------------------------------------- 1 | // 2 | // MyDocument.m 3 | // MarkEdit 4 | // 5 | // Created by bodhi on 31/03/10. 6 | // Copyright 2010 Apple Inc. All rights reserved. 7 | // 8 | 9 | #import "MarkdownDocument.h" 10 | #import "OgreKit/OgreKit.h" 11 | 12 | @implementation MarkdownDocument 13 | @synthesize string; 14 | 15 | - (id)init 16 | { 17 | self = [super init]; 18 | if (self) { 19 | // If an error occurs here, send a [self release] message and return nil. 20 | } 21 | return self; 22 | } 23 | 24 | - (NSString *)windowNibName 25 | { 26 | // Override returning the nib file name of the document 27 | // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead. 28 | return @"MyDocument"; 29 | } 30 | 31 | - (void)windowControllerDidLoadNib:(NSWindowController *) aController 32 | { 33 | [super windowControllerDidLoadNib:aController]; 34 | if (self.string != nil) { 35 | mdDelegate.baseURL = [self fileURL]; 36 | [[textView textStorage] setAttributedString:self.string]; 37 | } 38 | } 39 | 40 | - (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError 41 | { 42 | return [[[textView string] stringByReplacingOccurrencesOfString:mdDelegate.attachmentChar withString:@""] dataUsingEncoding:NSUTF8StringEncoding]; 43 | } 44 | 45 | - (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError 46 | { 47 | NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 48 | if (content != nil) { 49 | self.string = [[NSMutableAttributedString alloc] initWithString:content]; 50 | [[textView textStorage] setAttributedString: self.string]; 51 | [content release]; 52 | return YES; 53 | } else { 54 | *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL]; 55 | return NO; 56 | } 57 | } 58 | 59 | - (void)makeTextLarger:(id)sender { 60 | [mdDelegate makeTextLarger:[textView textStorage]]; 61 | } 62 | 63 | - (void)makeTextSmaller:(id)sender { 64 | [mdDelegate makeTextSmaller:[textView textStorage]]; 65 | } 66 | 67 | - (void)makeTextStandardSize:(id)sender { 68 | [mdDelegate resetTextSize:[textView textStorage]]; 69 | } 70 | 71 | - (void)reload:(id)sender { 72 | NSLog(@"reparsing"); 73 | [mdDelegate markupString:[textView textStorage]]; 74 | } 75 | 76 | - (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize { 77 | originalRange = [mdDelegate visibleRange]; 78 | [mdDelegate setWidth:frameSize.width]; 79 | return frameSize; 80 | } 81 | 82 | - (void)windowDidResize:(NSNotification *)notification { 83 | [mdDelegate recenterOn:originalRange]; 84 | } 85 | 86 | - (void)windowWillExitFullScreen:(NSNotification *)notification { 87 | originalRange = [mdDelegate visibleRange]; 88 | } 89 | 90 | - (void)windowDidExitFullScreen:(NSNotification *)notification { 91 | [mdDelegate setWidth:[[notification object] frame].size.width]; 92 | [mdDelegate recenterOn:originalRange]; 93 | } 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /MarkEdit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1DDD582C0DA1D0D100B32029 /* MyDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58280DA1D0D100B32029 /* MyDocument.xib */; }; 11 | 1DDD582D0DA1D0D100B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD582A0DA1D0D100B32029 /* MainMenu.xib */; }; 12 | 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */; }; 13 | 8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165FFE840EACC02AAC07 /* InfoPlist.strings */; }; 14 | 8D15AC310486D014006FF6A4 /* MarkdownDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4ACFDCFA73011CA2CEA /* MarkdownDocument.m */; settings = {ATTRIBUTES = (); }; }; 15 | 8D15AC320486D014006FF6A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4B0FDCFA73011CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 16 | 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; 17 | CF426651116380530030C2BA /* MarkdownDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CF426650116380530030C2BA /* MarkdownDelegate.m */; }; 18 | CF42665A116382660030C2BA /* OgreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF426659116382660030C2BA /* OgreKit.framework */; }; 19 | CF6CFB01116E1DC40088ACCC /* OgreKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CF6CFAF2116E1D990088ACCC /* OgreKit.framework */; }; 20 | CFFFF3E613FC0B360062820D /* Inconsolata.otf in CopyFiles */ = {isa = PBXBuildFile; fileRef = CFFFF3E113FC09C20062820D /* Inconsolata.otf */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | CF6CFAF1116E1D990088ACCC /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */; 27 | proxyType = 2; 28 | remoteGlobalIDString = 8DC2EF5B0486A6940098B216; 29 | remoteInfo = "OgreKit (Full Features)"; 30 | }; 31 | CF6CFAF3116E1D990088ACCC /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */; 34 | proxyType = 2; 35 | remoteGlobalIDString = 4DC40BFC09150BDB0029A2A6; 36 | remoteInfo = "OgreKit (without Find Panel)"; 37 | }; 38 | CF6CFAF5116E1D990088ACCC /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */; 41 | proxyType = 2; 42 | remoteGlobalIDString = 4DC40C0409150C280029A2A6; 43 | remoteInfo = "Regular Expression Test"; 44 | }; 45 | CF6CFAF7116E1D990088ACCC /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */; 48 | proxyType = 2; 49 | remoteGlobalIDString = 4DC40C0F09150C3E0029A2A6; 50 | remoteInfo = "Find Panel Test"; 51 | }; 52 | CF6CFAF9116E1D990088ACCC /* PBXContainerItemProxy */ = { 53 | isa = PBXContainerItemProxy; 54 | containerPortal = CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */; 55 | proxyType = 2; 56 | remoteGlobalIDString = 4DC40C1A09150C730029A2A6; 57 | remoteInfo = "My Find Panel Example"; 58 | }; 59 | CF6CFAFB116E1D990088ACCC /* PBXContainerItemProxy */ = { 60 | isa = PBXContainerItemProxy; 61 | containerPortal = CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */; 62 | proxyType = 2; 63 | remoteGlobalIDString = 4DC40C3009150C9E0029A2A6; 64 | remoteInfo = "Replace With Attributes Test"; 65 | }; 66 | CF6CFAFD116E1D990088ACCC /* PBXContainerItemProxy */ = { 67 | isa = PBXContainerItemProxy; 68 | containerPortal = CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */; 69 | proxyType = 2; 70 | remoteGlobalIDString = 4DA7410F1142B26900E28DA7; 71 | remoteInfo = "GC Test"; 72 | }; 73 | /* End PBXContainerItemProxy section */ 74 | 75 | /* Begin PBXCopyFilesBuildPhase section */ 76 | CF42664811637E500030C2BA /* CopyFiles */ = { 77 | isa = PBXCopyFilesBuildPhase; 78 | buildActionMask = 2147483647; 79 | dstPath = ""; 80 | dstSubfolderSpec = 10; 81 | files = ( 82 | CF6CFB01116E1DC40088ACCC /* OgreKit.framework in CopyFiles */, 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | CFFFF3E513FC0B2F0062820D /* CopyFiles */ = { 87 | isa = PBXCopyFilesBuildPhase; 88 | buildActionMask = 2147483647; 89 | dstPath = Fonts; 90 | dstSubfolderSpec = 7; 91 | files = ( 92 | CFFFF3E613FC0B360062820D /* Inconsolata.otf in CopyFiles */, 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | /* End PBXCopyFilesBuildPhase section */ 97 | 98 | /* Begin PBXFileReference section */ 99 | 089C1660FE840EACC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 100 | 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 101 | 13E42FBA07B3F13500E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 102 | 1DDD58290DA1D0D100B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MyDocument.xib; sourceTree = ""; }; 103 | 1DDD582B0DA1D0D100B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 104 | 2564AD2C0F5327BB00F57823 /* MarkEdit_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkEdit_Prefix.pch; sourceTree = ""; }; 105 | 2A37F4ACFDCFA73011CA2CEA /* MarkdownDocument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MarkdownDocument.m; sourceTree = ""; }; 106 | 2A37F4AEFDCFA73011CA2CEA /* MarkdownDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkdownDocument.h; sourceTree = ""; }; 107 | 2A37F4B0FDCFA73011CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 108 | 2A37F4BAFDCFA73011CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = ""; }; 109 | 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 110 | 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 111 | 8D15AC360486D014006FF6A4 /* MarkEdit-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MarkEdit-Info.plist"; sourceTree = ""; }; 112 | 8D15AC370486D014006FF6A4 /* MarkEdit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MarkEdit.app; sourceTree = BUILT_PRODUCTS_DIR; }; 113 | CF42664F116380530030C2BA /* MarkdownDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkdownDelegate.h; sourceTree = ""; }; 114 | CF426650116380530030C2BA /* MarkdownDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MarkdownDelegate.m; sourceTree = ""; }; 115 | CF426659116382660030C2BA /* OgreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OgreKit.framework; path = /Users/bodhi/Code/cocoa/OgreKit_2_1_4/build/Debug/OgreKit.framework; sourceTree = ""; }; 116 | CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OgreKit.xcodeproj; path = ../OgreKit_2_1_4/OgreKit.xcodeproj; sourceTree = SOURCE_ROOT; }; 117 | CFFFF3E113FC09C20062820D /* Inconsolata.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Inconsolata.otf; sourceTree = ""; }; 118 | /* End PBXFileReference section */ 119 | 120 | /* Begin PBXFrameworksBuildPhase section */ 121 | 8D15AC330486D014006FF6A4 /* Frameworks */ = { 122 | isa = PBXFrameworksBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */, 126 | CF42665A116382660030C2BA /* OgreKit.framework in Frameworks */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | /* End PBXFrameworksBuildPhase section */ 131 | 132 | /* Begin PBXGroup section */ 133 | 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */, 137 | ); 138 | name = "Linked Frameworks"; 139 | sourceTree = ""; 140 | }; 141 | 1058C7A8FEA54F5311CA2CBB /* Other Frameworks */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */, 145 | 13E42FBA07B3F13500E4EEF1 /* CoreData.framework */, 146 | 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */, 147 | ); 148 | name = "Other Frameworks"; 149 | sourceTree = ""; 150 | }; 151 | 19C28FB0FE9D524F11CA2CBB /* Products */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 8D15AC370486D014006FF6A4 /* MarkEdit.app */, 155 | ); 156 | name = Products; 157 | sourceTree = ""; 158 | }; 159 | 2A37F4AAFDCFA73011CA2CEA /* MarkEdit */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */, 163 | 2A37F4ABFDCFA73011CA2CEA /* Classes */, 164 | 2A37F4AFFDCFA73011CA2CEA /* Other Sources */, 165 | 2A37F4B8FDCFA73011CA2CEA /* Resources */, 166 | 2A37F4C3FDCFA73011CA2CEA /* Frameworks */, 167 | 19C28FB0FE9D524F11CA2CBB /* Products */, 168 | ); 169 | name = MarkEdit; 170 | sourceTree = ""; 171 | }; 172 | 2A37F4ABFDCFA73011CA2CEA /* Classes */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 2A37F4AEFDCFA73011CA2CEA /* MarkdownDocument.h */, 176 | 2A37F4ACFDCFA73011CA2CEA /* MarkdownDocument.m */, 177 | CF42664F116380530030C2BA /* MarkdownDelegate.h */, 178 | CF426650116380530030C2BA /* MarkdownDelegate.m */, 179 | ); 180 | name = Classes; 181 | sourceTree = ""; 182 | }; 183 | 2A37F4AFFDCFA73011CA2CEA /* Other Sources */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 2564AD2C0F5327BB00F57823 /* MarkEdit_Prefix.pch */, 187 | 2A37F4B0FDCFA73011CA2CEA /* main.m */, 188 | ); 189 | name = "Other Sources"; 190 | sourceTree = ""; 191 | }; 192 | 2A37F4B8FDCFA73011CA2CEA /* Resources */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | CFFFF3E113FC09C20062820D /* Inconsolata.otf */, 196 | 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */, 197 | 8D15AC360486D014006FF6A4 /* MarkEdit-Info.plist */, 198 | 089C165FFE840EACC02AAC07 /* InfoPlist.strings */, 199 | 1DDD58280DA1D0D100B32029 /* MyDocument.xib */, 200 | 1DDD582A0DA1D0D100B32029 /* MainMenu.xib */, 201 | ); 202 | name = Resources; 203 | sourceTree = ""; 204 | }; 205 | 2A37F4C3FDCFA73011CA2CEA /* Frameworks */ = { 206 | isa = PBXGroup; 207 | children = ( 208 | 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */, 209 | 1058C7A8FEA54F5311CA2CBB /* Other Frameworks */, 210 | CF426659116382660030C2BA /* OgreKit.framework */, 211 | ); 212 | name = Frameworks; 213 | sourceTree = ""; 214 | }; 215 | CF6CFAE2116E1D990088ACCC /* Products */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | CF6CFAF2116E1D990088ACCC /* OgreKit.framework */, 219 | CF6CFAF4116E1D990088ACCC /* OgreKit.framework */, 220 | CF6CFAF6116E1D990088ACCC /* OgreTest.app */, 221 | CF6CFAF8116E1D990088ACCC /* OgreFindPanelTest.app */, 222 | CF6CFAFA116E1D990088ACCC /* MyFindPanelExample.app */, 223 | CF6CFAFC116E1D990088ACCC /* ReplaceWithAttributesTest.app */, 224 | CF6CFAFE116E1D990088ACCC /* GCTest.app */, 225 | ); 226 | name = Products; 227 | sourceTree = ""; 228 | }; 229 | /* End PBXGroup section */ 230 | 231 | /* Begin PBXNativeTarget section */ 232 | 8D15AC270486D014006FF6A4 /* MarkEdit */ = { 233 | isa = PBXNativeTarget; 234 | buildConfigurationList = C05733C708A9546B00998B17 /* Build configuration list for PBXNativeTarget "MarkEdit" */; 235 | buildPhases = ( 236 | 8D15AC2B0486D014006FF6A4 /* Resources */, 237 | 8D15AC300486D014006FF6A4 /* Sources */, 238 | 8D15AC330486D014006FF6A4 /* Frameworks */, 239 | CF42664811637E500030C2BA /* CopyFiles */, 240 | CFFFF3E513FC0B2F0062820D /* CopyFiles */, 241 | ); 242 | buildRules = ( 243 | ); 244 | dependencies = ( 245 | ); 246 | name = MarkEdit; 247 | productInstallPath = "$(HOME)/Applications"; 248 | productName = MarkEdit; 249 | productReference = 8D15AC370486D014006FF6A4 /* MarkEdit.app */; 250 | productType = "com.apple.product-type.application"; 251 | }; 252 | /* End PBXNativeTarget section */ 253 | 254 | /* Begin PBXProject section */ 255 | 2A37F4A9FDCFA73011CA2CEA /* Project object */ = { 256 | isa = PBXProject; 257 | attributes = { 258 | LastUpgradeCheck = 0420; 259 | }; 260 | buildConfigurationList = C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "MarkEdit" */; 261 | compatibilityVersion = "Xcode 3.2"; 262 | developmentRegion = English; 263 | hasScannedForEncodings = 1; 264 | knownRegions = ( 265 | en, 266 | ); 267 | mainGroup = 2A37F4AAFDCFA73011CA2CEA /* MarkEdit */; 268 | projectDirPath = ""; 269 | projectReferences = ( 270 | { 271 | ProductGroup = CF6CFAE2116E1D990088ACCC /* Products */; 272 | ProjectRef = CF6CFAE1116E1D990088ACCC /* OgreKit.xcodeproj */; 273 | }, 274 | ); 275 | projectRoot = ""; 276 | targets = ( 277 | 8D15AC270486D014006FF6A4 /* MarkEdit */, 278 | ); 279 | }; 280 | /* End PBXProject section */ 281 | 282 | /* Begin PBXReferenceProxy section */ 283 | CF6CFAF2116E1D990088ACCC /* OgreKit.framework */ = { 284 | isa = PBXReferenceProxy; 285 | fileType = wrapper.framework; 286 | path = OgreKit.framework; 287 | remoteRef = CF6CFAF1116E1D990088ACCC /* PBXContainerItemProxy */; 288 | sourceTree = BUILT_PRODUCTS_DIR; 289 | }; 290 | CF6CFAF4116E1D990088ACCC /* OgreKit.framework */ = { 291 | isa = PBXReferenceProxy; 292 | fileType = wrapper.framework; 293 | path = OgreKit.framework; 294 | remoteRef = CF6CFAF3116E1D990088ACCC /* PBXContainerItemProxy */; 295 | sourceTree = BUILT_PRODUCTS_DIR; 296 | }; 297 | CF6CFAF6116E1D990088ACCC /* OgreTest.app */ = { 298 | isa = PBXReferenceProxy; 299 | fileType = wrapper.application; 300 | path = OgreTest.app; 301 | remoteRef = CF6CFAF5116E1D990088ACCC /* PBXContainerItemProxy */; 302 | sourceTree = BUILT_PRODUCTS_DIR; 303 | }; 304 | CF6CFAF8116E1D990088ACCC /* OgreFindPanelTest.app */ = { 305 | isa = PBXReferenceProxy; 306 | fileType = wrapper.application; 307 | path = OgreFindPanelTest.app; 308 | remoteRef = CF6CFAF7116E1D990088ACCC /* PBXContainerItemProxy */; 309 | sourceTree = BUILT_PRODUCTS_DIR; 310 | }; 311 | CF6CFAFA116E1D990088ACCC /* MyFindPanelExample.app */ = { 312 | isa = PBXReferenceProxy; 313 | fileType = wrapper.application; 314 | path = MyFindPanelExample.app; 315 | remoteRef = CF6CFAF9116E1D990088ACCC /* PBXContainerItemProxy */; 316 | sourceTree = BUILT_PRODUCTS_DIR; 317 | }; 318 | CF6CFAFC116E1D990088ACCC /* ReplaceWithAttributesTest.app */ = { 319 | isa = PBXReferenceProxy; 320 | fileType = wrapper.application; 321 | path = ReplaceWithAttributesTest.app; 322 | remoteRef = CF6CFAFB116E1D990088ACCC /* PBXContainerItemProxy */; 323 | sourceTree = BUILT_PRODUCTS_DIR; 324 | }; 325 | CF6CFAFE116E1D990088ACCC /* GCTest.app */ = { 326 | isa = PBXReferenceProxy; 327 | fileType = wrapper.application; 328 | path = GCTest.app; 329 | remoteRef = CF6CFAFD116E1D990088ACCC /* PBXContainerItemProxy */; 330 | sourceTree = BUILT_PRODUCTS_DIR; 331 | }; 332 | /* End PBXReferenceProxy section */ 333 | 334 | /* Begin PBXResourcesBuildPhase section */ 335 | 8D15AC2B0486D014006FF6A4 /* Resources */ = { 336 | isa = PBXResourcesBuildPhase; 337 | buildActionMask = 2147483647; 338 | files = ( 339 | 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */, 340 | 8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */, 341 | 1DDD582C0DA1D0D100B32029 /* MyDocument.xib in Resources */, 342 | 1DDD582D0DA1D0D100B32029 /* MainMenu.xib in Resources */, 343 | ); 344 | runOnlyForDeploymentPostprocessing = 0; 345 | }; 346 | /* End PBXResourcesBuildPhase section */ 347 | 348 | /* Begin PBXSourcesBuildPhase section */ 349 | 8D15AC300486D014006FF6A4 /* Sources */ = { 350 | isa = PBXSourcesBuildPhase; 351 | buildActionMask = 2147483647; 352 | files = ( 353 | 8D15AC310486D014006FF6A4 /* MarkdownDocument.m in Sources */, 354 | 8D15AC320486D014006FF6A4 /* main.m in Sources */, 355 | CF426651116380530030C2BA /* MarkdownDelegate.m in Sources */, 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | /* End PBXSourcesBuildPhase section */ 360 | 361 | /* Begin PBXVariantGroup section */ 362 | 089C165FFE840EACC02AAC07 /* InfoPlist.strings */ = { 363 | isa = PBXVariantGroup; 364 | children = ( 365 | 089C1660FE840EACC02AAC07 /* English */, 366 | ); 367 | name = InfoPlist.strings; 368 | sourceTree = ""; 369 | }; 370 | 1DDD58280DA1D0D100B32029 /* MyDocument.xib */ = { 371 | isa = PBXVariantGroup; 372 | children = ( 373 | 1DDD58290DA1D0D100B32029 /* English */, 374 | ); 375 | name = MyDocument.xib; 376 | sourceTree = ""; 377 | }; 378 | 1DDD582A0DA1D0D100B32029 /* MainMenu.xib */ = { 379 | isa = PBXVariantGroup; 380 | children = ( 381 | 1DDD582B0DA1D0D100B32029 /* English */, 382 | ); 383 | name = MainMenu.xib; 384 | sourceTree = ""; 385 | }; 386 | 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */ = { 387 | isa = PBXVariantGroup; 388 | children = ( 389 | 2A37F4BAFDCFA73011CA2CEA /* English */, 390 | ); 391 | name = Credits.rtf; 392 | sourceTree = ""; 393 | }; 394 | /* End PBXVariantGroup section */ 395 | 396 | /* Begin XCBuildConfiguration section */ 397 | C05733C808A9546B00998B17 /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ALWAYS_SEARCH_USER_PATHS = NO; 401 | COPY_PHASE_STRIP = NO; 402 | FRAMEWORK_SEARCH_PATHS = ( 403 | "$(inherited)", 404 | "\"$(SRCROOT)/../OgreKit_2_1_4/build/Debug\"", 405 | ); 406 | GCC_DYNAMIC_NO_PIC = NO; 407 | GCC_MODEL_TUNING = G5; 408 | GCC_OPTIMIZATION_LEVEL = 0; 409 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 410 | GCC_PREFIX_HEADER = MarkEdit_Prefix.pch; 411 | INFOPLIST_FILE = "MarkEdit-Info.plist"; 412 | INSTALL_PATH = "$(HOME)/Applications"; 413 | PRODUCT_NAME = MarkEdit; 414 | SDKROOT = macosx10.6; 415 | }; 416 | name = Debug; 417 | }; 418 | C05733C908A9546B00998B17 /* Release */ = { 419 | isa = XCBuildConfiguration; 420 | buildSettings = { 421 | ALWAYS_SEARCH_USER_PATHS = NO; 422 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 423 | FRAMEWORK_SEARCH_PATHS = ( 424 | "$(inherited)", 425 | "\"$(SRCROOT)/../OgreKit_2_1_4/build/Debug\"", 426 | ); 427 | GCC_MODEL_TUNING = G5; 428 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 429 | GCC_PREFIX_HEADER = MarkEdit_Prefix.pch; 430 | INFOPLIST_FILE = "MarkEdit-Info.plist"; 431 | INSTALL_PATH = "$(HOME)/Applications"; 432 | PRODUCT_NAME = MarkEdit; 433 | SDKROOT = macosx10.6; 434 | }; 435 | name = Release; 436 | }; 437 | C05733CC08A9546B00998B17 /* Debug */ = { 438 | isa = XCBuildConfiguration; 439 | buildSettings = { 440 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 441 | GCC_C_LANGUAGE_STANDARD = gnu99; 442 | GCC_OPTIMIZATION_LEVEL = 0; 443 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 444 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 445 | GCC_WARN_UNUSED_VARIABLE = YES; 446 | ONLY_ACTIVE_ARCH = YES; 447 | SDKROOT = macosx10.6; 448 | }; 449 | name = Debug; 450 | }; 451 | C05733CD08A9546B00998B17 /* Release */ = { 452 | isa = XCBuildConfiguration; 453 | buildSettings = { 454 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 455 | GCC_C_LANGUAGE_STANDARD = gnu99; 456 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 457 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 458 | GCC_WARN_UNUSED_VARIABLE = YES; 459 | ONLY_ACTIVE_ARCH = NO; 460 | SDKROOT = macosx10.6; 461 | }; 462 | name = Release; 463 | }; 464 | /* End XCBuildConfiguration section */ 465 | 466 | /* Begin XCConfigurationList section */ 467 | C05733C708A9546B00998B17 /* Build configuration list for PBXNativeTarget "MarkEdit" */ = { 468 | isa = XCConfigurationList; 469 | buildConfigurations = ( 470 | C05733C808A9546B00998B17 /* Debug */, 471 | C05733C908A9546B00998B17 /* Release */, 472 | ); 473 | defaultConfigurationIsVisible = 0; 474 | defaultConfigurationName = Release; 475 | }; 476 | C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "MarkEdit" */ = { 477 | isa = XCConfigurationList; 478 | buildConfigurations = ( 479 | C05733CC08A9546B00998B17 /* Debug */, 480 | C05733CD08A9546B00998B17 /* Release */, 481 | ); 482 | defaultConfigurationIsVisible = 0; 483 | defaultConfigurationName = Release; 484 | }; 485 | /* End XCConfigurationList section */ 486 | }; 487 | rootObject = 2A37F4A9FDCFA73011CA2CEA /* Project object */; 488 | } 489 | -------------------------------------------------------------------------------- /English.lproj/MyDocument.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1060 5 | 11A511 6 | 1617 7 | 1138 8 | 566.00 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 1617 12 | 13 | 14 | NSScrollView 15 | NSWindowTemplate 16 | NSView 17 | NSScroller 18 | NSCustomObject 19 | NSTextView 20 | 21 | 22 | com.apple.InterfaceBuilder.CocoaPlugin 23 | 24 | 25 | 26 | 27 | MarkdownDocument 28 | 29 | 30 | FirstResponder 31 | 32 | 33 | 271 34 | 2 35 | {{133, 3}, {716, 645}} 36 | 1886912512 37 | Window 38 | NSWindow 39 | View 40 | 41 | {94, 86} 42 | 43 | 44 | 256 45 | 46 | 47 | 48 | 274 49 | 50 | 51 | 52 | 2304 53 | 54 | 55 | 56 | 2322 57 | 58 | Apple HTML pasteboard type 59 | Apple PDF pasteboard type 60 | Apple PICT pasteboard type 61 | Apple PNG pasteboard type 62 | Apple URL pasteboard type 63 | CorePasteboardFlavorType 0x6D6F6F76 64 | NSColor pasteboard type 65 | NSFilenamesPboardType 66 | NSStringPboardType 67 | NeXT Encapsulated PostScript v1.2 pasteboard type 68 | NeXT RTFD pasteboard type 69 | NeXT Rich Text Format v1.0 pasteboard type 70 | NeXT TIFF v4.0 pasteboard type 71 | NeXT font pasteboard type 72 | NeXT ruler pasteboard type 73 | WebURLsWithTitlesPboardType 74 | public.url 75 | 76 | {719, 14} 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 134 92 | 93 | 94 | 95 | 719 96 | 1 97 | 98 | 99 | 67219439 100 | 0 101 | 102 | 103 | 3 104 | MQA 105 | 106 | 107 | 108 | 6 109 | System 110 | selectedTextBackgroundColor 111 | 112 | 3 113 | MC42NjY2NjY2NjY3AA 114 | 115 | 116 | 117 | 6 118 | System 119 | selectedTextColor 120 | 121 | 3 122 | MAA 123 | 124 | 125 | 126 | 127 | 128 | 129 | 1 130 | MCAwIDEAA 131 | 132 | 133 | {8, -8} 134 | 13 135 | 136 | 137 | 138 | 139 | 140 | 1 141 | 142 | 6 143 | {752, 10000000} 144 | {223, 0} 145 | 146 | 147 | 148 | {{1, 1}, {717, 643}} 149 | 150 | 151 | 152 | 153 | 154 | 155 | {4, 5} 156 | 157 | 12582912 158 | 159 | 160 | 161 | 162 | 163 | TU0AKgAAAHCAFUqgBVKsAAAAwdVQUqwaEQeIRGJRGFlYqwWLQ+JxuOQpVRmEx2RROKwOQyOUQSPyaUym 164 | SxqWyKXyeYxyZzWbSuJTScRCbz2Nz+gRKhUOfTqeUai0OSxiWTiBQSHSGFquGwekxyAgAAAOAQAAAwAA 165 | AAEAEAAAAQEAAwAAAAEAEAAAAQIAAwAAAAIACAAIAQMAAwAAAAEABQAAAQYAAwAAAAEAAQAAAREABAAA 166 | AAEAAAAIARIAAwAAAAEAAQAAARUAAwAAAAEAAgAAARYAAwAAAAEAEAAAARcABAAAAAEAAABnARwAAwAA 167 | AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 168 | 169 | 170 | 171 | 172 | 173 | 3 174 | MCAwAA 175 | 176 | 177 | 178 | 4 179 | 180 | 181 | 182 | -2147483392 183 | {{-100, -100}, {15, 623}} 184 | 185 | 186 | 187 | 188 | _doScroller: 189 | 0.85256409645080566 190 | 191 | 192 | 193 | -2147483392 194 | {{-100, -100}, {87, 18}} 195 | 196 | 197 | 198 | YES 199 | 1 200 | 201 | _doScroller: 202 | 1 203 | 0.94565218687057495 204 | 205 | 206 | {{-1, 0}, {719, 645}} 207 | 208 | 209 | 210 | 133778 211 | 212 | 213 | 214 | 215 | 216 | {716, 645} 217 | 218 | 219 | 220 | 221 | {{0, 0}, {1280, 778}} 222 | {94, 108} 223 | {10000000000000, 10000000000000} 224 | MarkEdit 225 | 128 226 | YES 227 | 228 | 229 | NSApplication 230 | 231 | 232 | MarkdownDelegate 233 | 234 | 235 | 236 | 237 | 238 | 239 | delegate 240 | 241 | 242 | 243 | 17 244 | 245 | 246 | 247 | window 248 | 249 | 250 | 251 | 18 252 | 253 | 254 | 255 | textView 256 | 257 | 258 | 259 | 100027 260 | 261 | 262 | 263 | mdDelegate 264 | 265 | 266 | 267 | 100032 268 | 269 | 270 | 271 | delegate 272 | 273 | 274 | 275 | 100034 276 | 277 | 278 | 279 | text 280 | 281 | 282 | 283 | 100035 284 | 285 | 286 | 287 | 288 | 289 | 0 290 | 291 | 292 | 293 | 294 | 295 | -2 296 | 297 | 298 | File's Owner 299 | 300 | 301 | -1 302 | 303 | 304 | First Responder 305 | 306 | 307 | 5 308 | 309 | 310 | 311 | 312 | 313 | Window 314 | 315 | 316 | 6 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | -3 325 | 326 | 327 | Application 328 | 329 | 330 | 100021 331 | 332 | 333 | 334 | 335 | 100022 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 100023 346 | 347 | 348 | 349 | 350 | 100024 351 | 352 | 353 | 354 | 355 | 100025 356 | 357 | 358 | 359 | 360 | 361 | 362 | com.apple.InterfaceBuilder.CocoaPlugin 363 | com.apple.InterfaceBuilder.CocoaPlugin 364 | com.apple.InterfaceBuilder.CocoaPlugin 365 | com.apple.InterfaceBuilder.CocoaPlugin 366 | com.apple.InterfaceBuilder.CocoaPlugin 367 | com.apple.InterfaceBuilder.CocoaPlugin 368 | com.apple.InterfaceBuilder.CocoaPlugin 369 | com.apple.InterfaceBuilder.CocoaPlugin 370 | com.apple.InterfaceBuilder.CocoaPlugin 371 | {{330, 107}, {716, 645}} 372 | com.apple.InterfaceBuilder.CocoaPlugin 373 | 374 | 375 | 376 | 377 | 378 | 100035 379 | 380 | 381 | 382 | 383 | MarkdownDelegate 384 | NSObject 385 | 386 | text 387 | NSTextView 388 | 389 | 390 | text 391 | 392 | text 393 | NSTextView 394 | 395 | 396 | 397 | IBProjectSource 398 | ./Classes/MarkdownDelegate.h 399 | 400 | 401 | 402 | MarkdownDocument 403 | NSDocument 404 | 405 | MarkdownDelegate 406 | NSTextView 407 | 408 | 409 | 410 | mdDelegate 411 | MarkdownDelegate 412 | 413 | 414 | textView 415 | NSTextView 416 | 417 | 418 | 419 | IBProjectSource 420 | ./Classes/MarkdownDocument.h 421 | 422 | 423 | 424 | NSDocument 425 | 426 | id 427 | id 428 | id 429 | id 430 | id 431 | id 432 | 433 | 434 | 435 | printDocument: 436 | id 437 | 438 | 439 | revertDocumentToSaved: 440 | id 441 | 442 | 443 | runPageLayout: 444 | id 445 | 446 | 447 | saveDocument: 448 | id 449 | 450 | 451 | saveDocumentAs: 452 | id 453 | 454 | 455 | saveDocumentTo: 456 | id 457 | 458 | 459 | 460 | IBProjectSource 461 | ./Classes/NSDocument.h 462 | 463 | 464 | 465 | 466 | 0 467 | IBCocoaFramework 468 | 469 | com.apple.InterfaceBuilder.CocoaPlugin.macosx 470 | 471 | 472 | YES 473 | 3 474 | 475 | 476 | -------------------------------------------------------------------------------- /MarkdownDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // MarkdownDelegate.m 3 | // MarkEdit 4 | // 5 | // Created by bodhi on 1/04/10. 6 | // Copyright 2010 Apple Inc. All rights reserved. 7 | // 8 | 9 | #import "MarkdownDelegate.h" 10 | #import "OgreKit/OgreKit.h" 11 | 12 | static NSString *listType = @"list"; 13 | static NSString *refType = @"ref"; 14 | static NSString *headerType = @"header"; 15 | static NSString *quoteType = @"quote"; 16 | static NSString *codeType = @"code"; 17 | static NSString *hrType = @"hr"; 18 | static NSString *plainType = @"plain"; 19 | static NSString *setexType = @"setex"; 20 | static NSString *setexMarkerType = @"setexMarker"; 21 | static NSString *indentType = @"indent"; 22 | static NSString *emptyType = @"empty"; 23 | 24 | @interface MDBlock : NSObject { 25 | NSString *type; 26 | int indent; 27 | int prefixLength; 28 | OGRegularExpressionMatch *match; 29 | } 30 | @property(retain) NSString *type; 31 | @property(retain) OGRegularExpressionMatch *match; 32 | @property(assign) int indent; 33 | @property(assign) int prefixLength; 34 | @end 35 | @implementation MDBlock 36 | @synthesize type; 37 | @synthesize indent; 38 | @synthesize prefixLength; 39 | @synthesize match; 40 | - (id) initWithType:(NSString *)_type indent:(int)_indent prefix:(int)_prefixLength match:(OGRegularExpressionMatch *)_match { 41 | if (self = [super init]) { 42 | self.type = _type; 43 | self.indent = _indent; 44 | self.prefixLength = _prefixLength; 45 | self.match = _match; 46 | } 47 | return self; 48 | } 49 | 50 | + (id) blockWithType:(NSString *)type indent:(int)indent prefix:(int)prefixLength match:(OGRegularExpressionMatch *)match { 51 | return [[[MDBlock alloc] initWithType:type indent:indent prefix:prefixLength match:match] autorelease]; 52 | } 53 | 54 | - (id)copyWithZone:(NSZone *)zone { 55 | return [MDBlock blockWithType:self.type indent:self.indent prefix:self.prefixLength match:self.match]; 56 | } 57 | 58 | - (NSString *)description { 59 | return [NSString stringWithFormat:@"%@ indent:%d prefix:%d", type, indent, prefixLength]; 60 | } 61 | @end 62 | 63 | @interface NSMutableArray (MarkEdit) 64 | - (id)firstObject; 65 | @end 66 | @implementation NSMutableArray (MarkEdit) 67 | - (id)firstObject { 68 | return [self objectAtIndex:0]; 69 | } 70 | @end 71 | 72 | @interface MDStack : NSObject { 73 | NSRange range; 74 | NSMutableArray *array; 75 | } 76 | @property(assign) NSRange range; 77 | @property(retain) NSMutableArray *array; 78 | @end 79 | @implementation MDStack 80 | @synthesize range; 81 | @synthesize array; 82 | + (id) mdStackWith:(NSMutableArray *)arr range:(NSRange)range { 83 | MDStack *stack = [[MDStack alloc] init]; 84 | stack.array = arr; 85 | stack.range = range; 86 | return [stack autorelease]; 87 | } 88 | + (id) mdStackWith:(NSMutableArray *)arr { 89 | MDStack *stack = [[MDStack alloc] init]; 90 | stack.array = arr; 91 | return [stack autorelease]; 92 | } 93 | - (NSString *)description { 94 | return [NSString stringWithFormat:@"{%d,%d}:%@", range.location, range.length, [array description]]; 95 | } 96 | @end 97 | 98 | @implementation MarkdownDelegate 99 | @synthesize text; 100 | @synthesize attachmentChar; 101 | @synthesize baseURL; 102 | 103 | - (void) configureTextStyles { 104 | 105 | int lineHeight = 1.5 * baseFontSize; 106 | if (defaultStyle == nil) { 107 | defaultStyle = [[NSMutableParagraphStyle alloc] init]; 108 | } 109 | [defaultStyle setMinimumLineHeight:lineHeight]; 110 | [defaultStyle setMaximumLineHeight:lineHeight]; 111 | 112 | NSColor *grey = [NSColor lightGrayColor]; 113 | NSFont *normal = [NSFont fontWithName:@"Times" size:baseFontSize]; //[NSFont userFontOfSize:14]; 114 | 115 | defaultAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: 116 | defaultStyle, NSParagraphStyleAttributeName, 117 | normal, NSFontAttributeName, 118 | nil 119 | ] retain]; 120 | 121 | NSMutableParagraphStyle *ps; 122 | 123 | // ps = [defaultStyle mutableCopy]; 124 | blockquoteAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: 125 | // defaultStyle, NSParagraphStyleAttributeName, 126 | [NSFont fontWithName:@"Times-Italic" size:baseFontSize], NSFontAttributeName, 127 | nil 128 | ] retain]; 129 | 130 | metaAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: 131 | grey, NSForegroundColorAttributeName, 132 | nil 133 | ] retain]; 134 | 135 | ps = [defaultStyle mutableCopy]; 136 | [ps setLineBreakMode:NSLineBreakByTruncatingTail]; 137 | codeAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: 138 | [NSColor colorWithCalibratedWhite:0.95 alpha:1.0], NSBackgroundColorAttributeName, 139 | ps, NSParagraphStyleAttributeName, 140 | [[[NSObject alloc] init] autorelease], MarkdownCodeSection, 141 | nil 142 | ] retain]; 143 | 144 | strongAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: 145 | nil 146 | ] retain]; 147 | 148 | emAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: 149 | nil 150 | ] retain]; 151 | 152 | // ps = [defaultStyle mutableCopy]; 153 | h1Attributes = [[NSDictionary dictionaryWithObjectsAndKeys: 154 | // defaultStyle, NSParagraphStyleAttributeName, 155 | [NSNumber numberWithInt:-1], NSKernAttributeName, 156 | nil 157 | ] retain]; 158 | 159 | h2Attributes = [[NSDictionary dictionaryWithObjectsAndKeys: 160 | // defaultStyle, NSParagraphStyleAttributeName, 161 | [NSNumber numberWithInt:-1], NSKernAttributeName, 162 | nil 163 | ] retain]; 164 | 165 | ps = [defaultStyle mutableCopy]; 166 | [ps setAlignment:NSCenterTextAlignment]; 167 | hrAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: 168 | ps, NSParagraphStyleAttributeName, 169 | normal, NSFontAttributeName, 170 | nil 171 | ] retain]; 172 | } 173 | 174 | - (void)awakeFromNib { 175 | baseFontSize = 16; 176 | 177 | [text textStorage].delegate = self; 178 | 179 | [self setWidth:[text frame].size.width]; 180 | 181 | references = [[NSMutableDictionary alloc] init]; 182 | newReferences = false; 183 | 184 | MarkdownCodeSection = @"MarkdownCodeSection"; 185 | 186 | [self configureTextStyles]; 187 | 188 | NSTextAttachment *a = [[NSTextAttachment alloc] init]; 189 | attachmentChar = [[[NSAttributedString attributedStringWithAttachment:a] string] retain]; 190 | [a release]; 191 | 192 | NSString *urlSuffix = @"\\((\\S+?)\\s*(\\\".+?\\\")?\\)"; // 1: url, 2: title 193 | NSString *refSuffix = @"\\[(.+?)\\]"; // 1: reference 194 | // 1: suffix, 2: url, 3: title, 4: ref 195 | NSString *linkSuffix = [NSString stringWithFormat:@"(%@|%@)", urlSuffix, refSuffix]; 196 | 197 | // 1: text, 2: suffix, 3: url, 4: title, 5: ref 198 | NSString *baseRegex = [NSString stringWithFormat:@"\\[(.*?)\\]%@", linkSuffix]; 199 | 200 | imageNoAttachment = [[OGRegularExpression alloc] initWithString:[NSString stringWithFormat:@"!%@", baseRegex]]; 201 | 202 | // 1: attachment, 2: text, 3: suffix, 4: url, 5: title, 6: ref 203 | attachedImage = [[OGRegularExpression alloc] initWithString:[NSString stringWithFormat:@"!(%@)%@", attachmentChar, baseRegex]]; 204 | 205 | // ! with attachment char and no image markup, or attachment char with markup but no leading ! 206 | // 1: attachment 2: text, 3: suffix, 5: url, 5: title, 6: ref, 7: attachment 207 | attachmentNoImage = [[OGRegularExpression alloc] initWithString:[NSString stringWithFormat:@"(?:[^!](%@)%@|!(%@)(?!%@))", attachmentChar, baseRegex, attachmentChar, baseRegex]]; 208 | 209 | // ! (optional attachment char) [title] (uri) 210 | NSString *imageString = [NSString stringWithFormat:@"!%@?%@", attachmentChar, baseRegex]; 211 | image = [[OGRegularExpression alloc] initWithString:imageString]; 212 | 213 | inlinePattern = [[OGRegularExpression alloc] initWithString:@"\ 214 | (? \ 216 | (?[*_`]) \ 217 | \\k? \ 218 | ) \ 219 | (?(\\S.+?\\S|\\S+)) \ 220 | (? \ 221 | (? \ 223 | ) \ 224 | " options:OgreExtendOption]; 225 | 226 | linkRegex = [[OGRegularExpression alloc] initWithString:[NSString stringWithFormat:@"(?\\s+"], 242 | headerType, listType, quoteType, nil], quoteType, 243 | [NSArray arrayWithObjects:[OGRegularExpression regularExpressionWithString: 244 | @"^ {4}"], 245 | nil], codeType, 246 | [NSArray arrayWithObjects:hrRegexp, 247 | nil], hrType, 248 | [NSArray arrayWithObjects:[OGRegularExpression regularExpressionWithString: 249 | @"^(?=.)"], 250 | nil], plainType, 251 | [NSArray arrayWithObjects:[OGRegularExpression regularExpressionWithString: 252 | @"^[^\n\\S]+"], 253 | listType, nil], indentType, 254 | [NSArray arrayWithObjects:[OGRegularExpression regularExpressionWithString: 255 | @"^$"], 256 | nil], emptyType, 257 | [NSArray arrayWithObjects:[OGRegularExpression regularExpressionWithString: 258 | @"^([-=])\\1*\\s*$"], 259 | nil], setexMarkerType, 260 | nil]; 261 | 262 | // setex = /^([-=])\1*\s*$/ 263 | setex = [[OGRegularExpression alloc] initWithString:@"^([-=])\\1*\\s*$"]; 264 | 265 | // @indented = /^\s+(?=\S)/ 266 | indented = [[OGRegularExpression alloc] initWithString:@"^\\s+(?=\\S)"]; 267 | 268 | bareLink = [[OGRegularExpression alloc] initWithString:@"<(?[a-zA-Z][a-zA-Z0-9+.-]*:[^>]+)>"]; 269 | 270 | mainOrder = [[NSArray alloc] initWithObjects:setexMarkerType, hrType, refType, headerType, quoteType, listType, indentType, emptyType, plainType, nil]; 271 | lineBlocks = [[NSArray alloc] initWithObjects:hrType, refType, headerType, setexType, nil]; 272 | 273 | // Add single space to force setting default attributes on new document 274 | NSTextStorage *storage = [text textStorage]; 275 | if ([storage length] == 0) { 276 | NSMutableAttributedString *s = [[NSMutableAttributedString alloc] initWithString:@" "]; 277 | [storage beginEditing]; 278 | [storage appendAttributedString:s]; 279 | [storage endEditing]; 280 | [s release]; 281 | NSRange r = {0,1}; 282 | [storage beginEditing]; 283 | [storage deleteCharactersInRange:r]; 284 | [storage endEditing]; 285 | } 286 | } 287 | 288 | - (int)attachImage:(NSURL *)url toString:(NSMutableAttributedString *)target atIndex:(int) index { 289 | // NSLog(@"Image with src %@", imageSrc); 290 | 291 | NSError *error = nil; 292 | // NSLog(@"URL scheme: %@", [url scheme]); 293 | if (url && [[url scheme] isEqualToString:@"file"]) { 294 | NSFileWrapper *wrapper = [[NSFileWrapper alloc] initWithURL:url options:NSFileWrapperReadingWithoutMapping error:&error]; 295 | if (wrapper) { 296 | // NSLog(@"Wrapper: %@ error: %@", wrapper, error); 297 | NSTextAttachment *img = [[NSTextAttachment alloc] initWithFileWrapper:wrapper]; 298 | NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:img]; 299 | 300 | // NSLog(@"INSERTING %@ of length %d", imageString, [imageString length]); 301 | [target beginEditing]; 302 | [target insertAttributedString:imageString atIndex:index]; 303 | [target endEditing]; 304 | [img release]; 305 | [wrapper release]; 306 | } else { 307 | // NSLog(@"No file for %@", url); 308 | } 309 | return 1; 310 | } 311 | return 0; 312 | } 313 | 314 | - (NSString *)urlForReference:(NSString *)link { 315 | return [references objectForKey:link]; 316 | } 317 | 318 | - (void)addReference:(NSString *)urlString forKey:ref { 319 | if (urlString != nil) { 320 | [references setObject:urlString forKey:ref]; 321 | newReferences = true; 322 | } 323 | } 324 | 325 | - (NSString *)urlStringForString:(NSString *)urlString orReference:(NSString *)reference { 326 | if (urlString != nil && [urlString length] > 0) { // url 327 | return urlString; 328 | } else { // reference 329 | return [self urlForReference:reference]; 330 | } 331 | } 332 | 333 | - (NSURL *)urlForString:(NSString *)urlString orReference:(NSString *)reference { 334 | urlString = [self urlStringForString:urlString orReference:reference]; 335 | return (urlString != nil ? [NSURL URLWithString:urlString relativeToURL:baseURL] : nil); 336 | } 337 | 338 | - (void)textStorageWillProcessEditing:(NSNotification *)aNotification { 339 | NSTextStorage *storage = [aNotification object]; 340 | NSString *stString = [storage string]; 341 | 342 | OGRegularExpressionMatch *match; 343 | 344 | // find attachment with no markup 345 | for (match in [attachmentNoImage matchEnumeratorInString:stString]) { 346 | // 1: attachment 2: text, 3: suffix, 5: url, 5: title, 6: ref, 7: attachment 347 | 348 | // remove attachment 349 | // NSLog(@"ATTACHMENT NO IMAGE:%@", [match matchedString]); 350 | NSRange early = [match rangeOfSubstringAtIndex:1]; 351 | NSRange late = [match rangeOfSubstringAtIndex:7]; 352 | [storage beginEditing]; 353 | if (early.location != NSNotFound) [storage replaceCharactersInRange:early withString:@""]; 354 | if (late.location != NSNotFound) [storage replaceCharactersInRange:late withString:@""]; 355 | [storage endEditing]; 356 | } 357 | 358 | // find image with attachment char 359 | // Do this before adding attachments so incorrect images get fixed 360 | int deletions = 0; 361 | for (match in [attachedImage matchEnumeratorInString:stString]) { 362 | // 1: attachment, 2: text, 3: suffix, 4: url, 5: title, 6: ref 363 | // NSLog(@"IMAGE WITH ATTACHMENT: %@", [match matchedString]); 364 | 365 | NSString *src = [self urlStringForString:[match substringAtIndex:4] orReference:[match substringAtIndex:6]]; 366 | 367 | NSRange attachmentRange = [match rangeOfSubstringAtIndex:1]; 368 | attachmentRange.location -= deletions; 369 | NSTextAttachment *attachment = [storage attribute:NSAttachmentAttributeName atIndex:attachmentRange.location effectiveRange:nil]; 370 | // NSLog(@"THE ATTACHMENT %@, the src %@ the char %@", attachment, src, [match substringAtIndex:1]); 371 | 372 | // validate attachment src 373 | if (![src isEqualToString:[[attachment fileWrapper] filename]]) { 374 | [storage beginEditing]; 375 | [storage replaceCharactersInRange:attachmentRange withString:@""]; 376 | deletions += 1; 377 | [storage endEditing]; 378 | // NSLog(@"attachment different to source, stripped"); 379 | } else { 380 | // NSLog(@"attachment name same as source"); 381 | } 382 | } 383 | 384 | // find image markup (without attachment char) 385 | // Do this after removing attachments with incorrect images 386 | int attachmentCompensation = 1; 387 | for (match in [imageNoAttachment matchEnumeratorInString:stString]) { 388 | // 1: text, 2: suffix, 3: url, 4: title, 5: ref 389 | 390 | NSURL *url = [self urlForString:[match substringAtIndex:3] orReference:[match substringAtIndex:5]]; 391 | // add attachment char with attachment 392 | // NSLog(@"IMAGE %@", [match matchedString]); 393 | NSRange imageRange = [match rangeOfMatchedString]; 394 | 395 | int adjustment = 0; 396 | // NSLog(@"ATTACHMENT: %@", url); 397 | adjustment = [self attachImage:url toString:storage atIndex:imageRange.location + attachmentCompensation]; 398 | attachmentCompensation += adjustment; 399 | } 400 | 401 | } 402 | 403 | - (bool)isCodeSection:(NSAttributedString *)string atIndex:(int) index { 404 | return [string attribute:MarkdownCodeSection atIndex:index effectiveRange:nil] != nil; 405 | } 406 | 407 | - (NSDictionary *)attributesForIndentTo:(int) indent prefixLength:(int) prefix { 408 | NSMutableParagraphStyle *ps; 409 | ps = [defaultStyle mutableCopy]; 410 | 411 | int pointIndent = indent * baseFontSize; 412 | int prefixWidth = prefix * baseFontSize; 413 | 414 | [ps setHeadIndent:pointIndent]; 415 | [ps setFirstLineHeadIndent:pointIndent - prefixWidth]; 416 | // [ps setTailIndent:-pointIndent]; 417 | return [NSDictionary dictionaryWithObject:ps forKey:NSParagraphStyleAttributeName]; 418 | } 419 | 420 | - (void)indent:(NSMutableAttributedString *)string range:(NSRange) range for:(NSArray *)stack { 421 | int level = 0; 422 | int prefixTotal = 0; 423 | for (MDBlock *block in stack) { 424 | if (block.type == listType || 425 | block.type == quoteType) { 426 | level += 1; 427 | prefixTotal += block.prefixLength; 428 | } 429 | } 430 | 431 | if (level > 0) [string addAttributes:[self attributesForIndentTo:level prefixLength:prefixTotal] range:range]; 432 | } 433 | 434 | - (NSFont *)fontOfString:(NSAttributedString *)string atIndex:(int)index { 435 | return [string attribute:NSFontAttributeName atIndex:index effectiveRange:nil]; 436 | } 437 | 438 | - (int)fontSizeOfString:(NSAttributedString *)string atIndex:(int)index { 439 | NSFont *font = [self fontOfString:string atIndex:index]; 440 | return (font != nil) ? [font pointSize] : baseFontSize; 441 | } 442 | 443 | - (NSFont *)codeFontForSize:(int)size { 444 | return [NSFont fontWithName:@"Inconsolata" size:baseFontSize]; //[NSFont userFontOfSize:14]; 445 | // return [NSFont userFixedPitchFontOfSize:size-3]; 446 | } 447 | 448 | - (NSFont *)emphasisedFont:(NSFont *)font { 449 | NSFontManager *fontManager = [NSFontManager sharedFontManager]; 450 | NSFontTraitMask trait = NSFontItalicTrait; 451 | if ([fontManager traitsOfFont:font] & NSItalicFontMask) { 452 | font = [fontManager convertFont:font toNotHaveTrait:trait]; 453 | } else { 454 | font = [fontManager convertFont:font toHaveTrait:trait]; 455 | } 456 | return font; 457 | } 458 | 459 | - (NSFont *)strongFont:(NSFont *)font { 460 | NSFontManager *fontManager = [NSFontManager sharedFontManager]; 461 | NSFontTraitMask trait = NSFontBoldTrait; 462 | if ([fontManager traitsOfFont:font] & NSBoldFontMask) { 463 | font = [fontManager convertFont:font toNotHaveTrait:trait]; 464 | } else { 465 | font = [fontManager convertFont:font toHaveTrait:trait]; 466 | } 467 | return font; 468 | } 469 | 470 | - (NSFont *)headerFontForFont:(NSFont *)font level:(int) level { 471 | NSFontManager *fontManager = [NSFontManager sharedFontManager]; 472 | 473 | level = level < 6 ? level : 6; 474 | int size; 475 | switch (level) { 476 | case 1: 477 | size = 1.5 * baseFontSize; 478 | break; 479 | case 2: 480 | size = 1.3125 * baseFontSize; 481 | break; 482 | case 3: 483 | case 4: 484 | size = 1.125 * baseFontSize; 485 | break; 486 | case 5: 487 | case 6: 488 | size = baseFontSize; 489 | break; 490 | } 491 | 492 | font = [fontManager convertFont:font toSize:size]; 493 | 494 | if (level != 1 && level % 2 == 1) 495 | font = [fontManager convertFont:font toHaveTrait:NSFontBoldTrait]; 496 | 497 | return font; 498 | } 499 | 500 | - (void)markAsMeta:(NSMutableAttributedString *)string range:(NSRange)range size:(int)size { 501 | NSFont *font = [self codeFontForSize:size]; 502 | 503 | [string addAttribute:NSFontAttributeName value:font range:range]; 504 | [string addAttributes:metaAttributes range:range]; 505 | } 506 | 507 | - (void)markAsMeta:(NSMutableAttributedString *)string range:(NSRange)range { 508 | int size = [self fontSizeOfString:string atIndex:range.location]; 509 | [self markAsMeta:string range:range size:size]; 510 | } 511 | 512 | typedef bool (^blockCheckFn)(MDBlock *bl); 513 | 514 | - (void) popBlocks:(NSMutableArray *)stack checkFn:(blockCheckFn)fn { 515 | MDBlock *block = [stack lastObject]; 516 | while (block != nil) { 517 | if (fn(block)) { 518 | [stack removeLastObject]; 519 | block = [stack lastObject]; 520 | } else { 521 | block = nil; 522 | } 523 | } 524 | } 525 | 526 | - (void) popLineBlocks:(NSMutableArray *)stack { 527 | [self popBlocks:stack checkFn:^(MDBlock *block) { 528 | return (bool) [lineBlocks containsObject:block.type]; 529 | }]; 530 | for (MDBlock *block in stack) 531 | block.prefixLength = 0; 532 | } 533 | 534 | - (void) popParagraphBlocks:(NSMutableArray *)stack { 535 | MDBlock *first = 0; 536 | if ([stack count] > 0) first = [stack objectAtIndex:0]; 537 | if (first == nil || first.type == listType) 538 | return; 539 | 540 | [self popBlocks:stack checkFn:^(MDBlock *block) { 541 | return (bool) (block.type != listType); 542 | }]; 543 | 544 | 545 | } 546 | 547 | - (void) pushParagraphBlock:(NSMutableArray *)stack block:(MDBlock *)newBlock { 548 | while ([stack count] > 0) { 549 | MDBlock *block = [stack lastObject]; 550 | if (block.indent >= newBlock.indent) { 551 | [stack removeLastObject]; 552 | } else { 553 | break; 554 | } 555 | } 556 | [stack addObject:newBlock]; 557 | } 558 | 559 | - (void)markLinks:(NSMutableAttributedString *)string range:(NSRange)range { 560 | for (OGRegularExpressionMatch *match in [linkRegex matchEnumeratorInAttributedString:string range:range]) { 561 | NSRange mRange = [match rangeOfMatchedString]; 562 | NSRange textRange = [match rangeOfSubstringAtIndex:1]; 563 | NSRange suffix = [match rangeOfSubstringAtIndex:7]; 564 | NSRange urlRange = [match rangeOfSubstringAtIndex:8]; 565 | // Do nothing with title for now 566 | // NSString *title = [match substringAtIndex:9]; 567 | 568 | NSRange refRange = [match rangeOfSubstringAtIndex:10]; 569 | NSURL *url = [self urlForString:[match substringAtIndex:8] orReference:[match substringAtIndex:10]]; 570 | // NSLog(@"'%@': text:'%@' suffix:'%@' url:'%@' title:'%@' ref:'%@'", [match matchedString], [match substringAtIndex:1], [match substringAtIndex:7], [match substringAtIndex:8], [match substringAtIndex:9], [match substringAtIndex:10]); 571 | 572 | suffix.location -= 1; // ']' before url+title 573 | suffix.length += 1; 574 | 575 | [self markAsMeta:string range:NSMakeRange(mRange.location, 1)]; // leading [ 576 | [self markAsMeta:string range:suffix]; 577 | if (url != nil) { 578 | [string addAttribute:NSLinkAttributeName value:url range:textRange]; 579 | } else { 580 | [self markAsMeta:string range:textRange]; 581 | [string addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:urlRange]; 582 | [string addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:refRange]; 583 | } 584 | } 585 | 586 | for (OGRegularExpressionMatch *match in [bareLink matchEnumeratorInAttributedString:string range:range]) { 587 | NSURL *url = [NSURL URLWithString:[match substringNamed:@"url"]]; 588 | if (url != nil) { 589 | [string addAttribute:NSLinkAttributeName value:url range:[match rangeOfMatchedString]]; 590 | } 591 | } 592 | 593 | } 594 | 595 | - (void)markImages:(NSMutableAttributedString *)string range:(NSRange)range { 596 | for (OGRegularExpressionMatch *match in [image matchEnumeratorInAttributedString:string range:range]) { 597 | [self markAsMeta:string range:[match rangeOfMatchedString]]; 598 | } 599 | } 600 | 601 | - (void)markInlineElementsIn:(NSMutableAttributedString *)string range:(NSRange)range { 602 | if (range.length <= 2) return; 603 | 604 | for (OGRegularExpressionMatch *match in [inlinePattern matchEnumeratorInAttributedString:string range:range]) { 605 | NSRange mRange = [match rangeOfMatchedString]; 606 | NSDictionary *attribs = nil; 607 | NSString *delimiter = [match substringNamed:@"delimiter"]; 608 | NSFont *font = [self fontOfString:string atIndex:[match rangeOfSubstringNamed:@"content"].location]; 609 | if (![self isCodeSection:string atIndex:[match rangeOfSubstringNamed:@"delimiter"].location]) { // don't set attributes in code blocks 610 | if ([delimiter isEqualToString:@"`"] || 611 | [delimiter isEqualToString:@"``"]) { // code span 612 | attribs = codeAttributes; 613 | font = [self codeFontForSize:[self fontSizeOfString:string atIndex:mRange.location]]; 614 | } else if ([delimiter isEqualToString:@"**"] || 615 | [delimiter isEqualToString:@"__"]) { // strong span 616 | attribs = strongAttributes; 617 | font = [self strongFont:font]; 618 | } else { // em span 619 | attribs = emAttributes; 620 | font = [self emphasisedFont:font]; 621 | } 622 | } 623 | 624 | if (attribs != nil) { 625 | [string addAttribute:NSFontAttributeName value:font range:mRange]; 626 | [string addAttributes:attribs range:mRange]; 627 | [self markAsMeta:string range:[match rangeOfSubstringNamed:@"delimiter"]]; 628 | [self markAsMeta:string range:[match rangeOfSubstringNamed:@"end_delimiter"]]; 629 | if (attribs != codeAttributes) [self markInlineElementsIn:string range:[match rangeOfSubstringNamed:@"content"]]; 630 | } 631 | } 632 | 633 | [self markImages:string range:range]; 634 | [self markLinks:string range:range]; 635 | } 636 | 637 | - (void) markLine:(NSMutableAttributedString *)line range:(NSRange) range stack:(NSArray *)stack { 638 | if (range.length > 0 && stack != nil) { 639 | 640 | // [line addAttribute:NSToolTipAttributeName value:[NSString stringWithFormat:@"%@", stack] range:range]; 641 | 642 | NSMutableArray *localStack = [NSMutableArray arrayWithArray:stack]; 643 | 644 | NSRange prefix = NSMakeRange(0,0); 645 | NSRange content = NSMakeRange(range.location, range.length); 646 | 647 | [self indent:line range:range for:localStack]; 648 | 649 | int prefixLength = 0; 650 | while ([localStack count] > 0) { 651 | MDBlock *block = [localStack objectAtIndex:0]; 652 | [localStack removeObjectAtIndex:0]; 653 | 654 | prefix = NSMakeRange(range.location + prefixLength, block.prefixLength); 655 | if (prefix.length > range.length) prefix.length = range.length; 656 | content = NSMakeRange(prefix.location + prefix.length, 0); 657 | prefixLength += block.prefixLength; 658 | 659 | if (range.location + range.length > content.location) 660 | content.length = range.location + range.length - content.location; 661 | 662 | if (prefix.length > 0) [self markAsMeta:line range:prefix]; 663 | 664 | // NSLog(@"%@: '%@' %d %d", block, [line string], prefix.length, all.length); 665 | // NSLog(@"%@ (%d %d): %@", stack, range.location, range.length, [[line attributedSubstringFromRange:content] string]); 666 | 667 | if (block.type == codeType) { 668 | [line addAttributes:codeAttributes range:range]; 669 | // NSLog(@"Not marking code tooltip"); 670 | // [line addAttribute:NSToolTipAttributeName value:[line attributedSubstringFromRange:content] range:range]; 671 | [line addAttribute:NSFontAttributeName value:[self codeFontForSize:baseFontSize] range:content]; 672 | } else if (block.type == headerType) { 673 | NSDictionary *attributes = h1Attributes; 674 | NSRange suffix = NSMakeRange(NSNotFound, 0); 675 | 676 | if (block.match != nil) { 677 | prefix = [block.match rangeOfSubstringAtIndex:1]; 678 | suffix = [block.match rangeOfSubstringAtIndex:2]; 679 | 680 | if (prefix.length == 1) { 681 | attributes = h1Attributes; 682 | } else { 683 | attributes = h2Attributes; 684 | } 685 | } 686 | 687 | NSFont *font = [self headerFontForFont:[self fontOfString:line atIndex:content.location] level:prefix.length]; 688 | [line addAttribute:NSFontAttributeName value:font range:content]; 689 | [line addAttributes:attributes range:content]; 690 | 691 | // need to mark suffix too 692 | if (suffix.location != NSNotFound && suffix.length > 0) { 693 | int size = [self fontSizeOfString:line atIndex:prefix.location]; 694 | [self markAsMeta:line range:suffix size:size]; 695 | } 696 | } else if (block.type == setexType) { 697 | NSDictionary *attributes = h1Attributes; 698 | NSString *delimiter = [block.match substringAtIndex:1]; 699 | bool isH1 = [delimiter isEqualToString:@"="]; 700 | if (!isH1) attributes = h2Attributes; 701 | NSFont *font = [self headerFontForFont:[self fontOfString:line atIndex:content.location] level:(isH1?1:2)]; 702 | [line addAttribute:NSFontAttributeName value:font range:content]; 703 | [line addAttributes:attributes range:content]; 704 | } else if (block.type == quoteType) { 705 | [line addAttributes:blockquoteAttributes range:content]; 706 | } else if (block.type == hrType) { 707 | [line addAttributes:hrAttributes range:prefix]; 708 | } else if (block.type == refType) { 709 | OGRegularExpressionMatch *match = block.match; 710 | NSString *ref = [match substringAtIndex:2]; 711 | NSString *url = [match substringAtIndex:3]; 712 | //NSString *title = [match substringAtIndex:4]; 713 | [self addReference:url forKey:ref]; 714 | } else { 715 | // other types 716 | //NSLog(@"Dunno what to do with type '%@'", block.type); 717 | } 718 | } 719 | 720 | if (content.length > 0) [self markInlineElementsIn:line range:content]; 721 | } 722 | } 723 | 724 | - (NSRange) range:(NSRange) range constrainedTo:(NSAttributedString *)string { 725 | int length = [string length]; 726 | if (range.location < 0) range.location = 0; 727 | if (range.location >= length) range.location = length == 0 ? 0 : length - 1; 728 | 729 | if (range.location + range.length > length) range.length = length - range.location; 730 | 731 | return range; 732 | } 733 | 734 | - (NSRange) expandRangeToParagraph:(NSRange) range forString:(NSAttributedString *)string { 735 | NSString *haystack = [string string]; 736 | NSString *needle = @"\n\n"; 737 | 738 | // Include current position in search 739 | NSRange prev = [self range:NSMakeRange(0, range.location + 1) constrainedTo:string]; 740 | NSRange next = NSMakeRange(range.location + range.length - 1, 0); 741 | next.length = [haystack length] - next.location; 742 | next = [self range:next constrainedTo:string]; 743 | 744 | prev = [haystack rangeOfString:needle options:NSBackwardsSearch range:prev]; 745 | if (prev.location != NSNotFound) { 746 | prev.length = prev.location; 747 | prev.location = 0; 748 | prev = [haystack rangeOfString:needle options:NSBackwardsSearch range:prev]; 749 | } 750 | next = [haystack rangeOfString:needle options:0 range:next]; 751 | if (next.location != NSNotFound) { 752 | next.location += 1; 753 | next.length = [haystack length] - next.location; 754 | next = [haystack rangeOfString:needle options:0 range:next]; 755 | } 756 | 757 | // Add one to get to the middle of \n\n, ie. the start of the blank 758 | // line, not the end of the previous paragraph 759 | range.location = prev.location == NSNotFound ? 0 : prev.location + 1; 760 | range.length = (next.location == NSNotFound ? [haystack length] : next.location + 1) - range.location; 761 | 762 | return range; 763 | } 764 | 765 | - (NSArray *)parseRegion:(NSRange)stringRange in:(NSMutableAttributedString *)string { 766 | NSMutableArray *stack = 0, *prevStack = 0, *data = 0; 767 | NSRange prevRange = NSMakeRange(NSNotFound, 0); 768 | 769 | data = [NSMutableArray array]; 770 | stack = [NSMutableArray array]; 771 | MDStack *stackInfo = [MDStack mdStackWith:stack]; 772 | [data addObject:stackInfo]; 773 | 774 | int indent = 0; 775 | 776 | for (OGRegularExpressionMatch *lineMatch in [[OGRegularExpression regularExpressionWithString:@"[^\\n]*\\n?"] matchEnumeratorInAttributedString:string range:stringRange]) { 777 | NSRange lRange = [lineMatch rangeOfMatchedString]; 778 | stackInfo.range = lRange; 779 | NSRange lineRange = NSMakeRange(lRange.location, lRange.length); 780 | OGRegularExpressionMatch *match; 781 | 782 | indent = 0; 783 | // Start with the default set of types to check (mainOrder). If 784 | // one matches, push that type on this line's stack of types, 785 | // adn replace the rest of the types to check with the types that 786 | // can nest inside the original matched type. 787 | // 788 | // E.g. default is `(quote, list, header)` matching against "* # 789 | // The header" quote doesn't match, remove it from list and move 790 | // on. 791 | // 792 | // List matches, so replace the rest of the types to check 793 | // (currently just `(header)`) with the types that can nest in a 794 | // list item `(header, list)`, and adjust the range of the string 795 | // to skip the inital "* ", leaving "# The header". Push 796 | // `listType` onto this line's block-type stack 797 | // 798 | // Try matching the list again: header matches, so replace the 799 | // list with what can succeed header (in header's case, nothing.), 800 | // push headerType onto the block stack, adjust the range to skip 801 | // the header markup "# " and loop again. 802 | // 803 | // Now the list of types that this line can be is empty, so we are done. 804 | NSMutableArray *order = [NSMutableArray arrayWithArray:mainOrder]; 805 | NSString *type; 806 | while ([order count] > 0) { 807 | type = [order objectAtIndex:0]; 808 | [order removeObjectAtIndex:0]; 809 | 810 | NSMutableArray *process = [NSMutableArray arrayWithArray:[blocks objectForKey:type]]; 811 | OGRegularExpression *regex = [process objectAtIndex:0]; 812 | [process removeObjectAtIndex:0]; 813 | 814 | if (match = [regex matchInAttributedString:string range:lineRange]) { 815 | NSRange mRange = [match rangeOfSubstringAtIndex:1]; 816 | if (mRange.location == NSNotFound) mRange = [match rangeOfMatchedString]; 817 | 818 | [self pushParagraphBlock:stack block:[MDBlock blockWithType:type indent:indent prefix:mRange.length match:match]]; 819 | indent += mRange.length; 820 | order = process; 821 | 822 | lineRange = NSMakeRange(lineRange.location + mRange.length, lineRange.length - mRange.length); 823 | } 824 | } 825 | 826 | if ([[stack objectAtIndex:0] type] == setexMarkerType) { 827 | // NSLog(@"Setex marker of %@", [[[stack objectAtIndex:0] match] substringAtIndex:1]); 828 | // NSLog(@"PrevStack %@", prevStack); 829 | 830 | if ((prevStack != nil && [[prevStack objectAtIndex:0] type] != emptyType) || [[[[stack objectAtIndex:0] match] substringAtIndex:1] isEqualToString:@"="]) { 831 | [prevStack removeAllObjects]; 832 | [self pushParagraphBlock:prevStack block:[MDBlock blockWithType:setexType indent:0 prefix:0 match:match]]; 833 | [[stack objectAtIndex:0] setPrefixLength:lRange.length]; 834 | } else if ([hrRegexp matchInAttributedString:string range:lRange] != nil) { 835 | [stack replaceObjectAtIndex:0 withObject:[MDBlock blockWithType:hrType indent:0 prefix:lRange.length match:match]]; 836 | } else { 837 | [stack replaceObjectAtIndex:0 withObject:[MDBlock blockWithType:plainType indent: 0 prefix:0 match:match]]; 838 | } 839 | } 840 | 841 | // NSLog(@"Final stack on |%@|: %@", [[string attributedSubstringFromRange:lRange] string], stack); 842 | prevStack = stack; 843 | stack = [NSMutableArray array]; 844 | stackInfo = [MDStack mdStackWith:stack]; 845 | [data addObject:stackInfo]; 846 | } 847 | 848 | [data removeLastObject]; 849 | return data; 850 | } 851 | 852 | - (NSMutableArray *)bareStack:(NSArray *)stack { 853 | NSMutableArray *newStack = [NSMutableArray array]; 854 | MDBlock *dup; 855 | for(MDBlock *block in stack) { 856 | dup = [block copy]; 857 | dup.prefixLength = 0; 858 | dup.indent = 0; 859 | [newStack addObject:dup]; 860 | } 861 | [self popLineBlocks:newStack]; 862 | return newStack; 863 | } 864 | 865 | - (NSMutableArray *)previousContentStack:(NSArray *)data before:(int)i { 866 | MDStack *prev = nil; 867 | // NSLog(@"starting at %d", i); 868 | while (i > 0) { 869 | i--; // find previous non-blank parse-line 870 | prev = [data objectAtIndex:i]; 871 | // NSLog(@"at %d type %@", i, [[prev.array firstObject] type]); 872 | if ([[prev.array firstObject] type] != plainType) return [self bareStack:prev.array]; 873 | } 874 | return nil; 875 | } 876 | 877 | - (NSMutableArray *)previousListStack:(NSArray *)data before:(int)i { 878 | NSString *iType; 879 | MDStack *stack = nil; 880 | bool crossedParagraph = NO; 881 | while (i > 0) { 882 | i--; 883 | stack = [data objectAtIndex:i]; 884 | iType = [[stack.array firstObject] type]; 885 | // NSLog(@"at %d type %@", i, iType); 886 | if (iType == listType) { 887 | return [NSArray arrayWithObject:[stack.array firstObject]]; 888 | } else if (iType != emptyType && iType != plainType && iType != indentType) { // Something that can't continue a list 889 | return nil; 890 | } else if (crossedParagraph && (iType != plainType || iType != listType)) { 891 | // Going backwards, a plain paragraph can only continue a list directly 892 | return nil; 893 | } else if (iType == plainType) { 894 | crossedParagraph = YES; 895 | } 896 | } 897 | return nil; 898 | } 899 | 900 | - (NSMutableArray *)mergeIndentedStack:(NSMutableArray *)right onto:(NSArray *)left { 901 | NSMutableArray *new = nil; 902 | int prefix = [[right firstObject] prefixLength]; 903 | for (MDBlock *block in left) { 904 | if (prefix < 0) break; 905 | prefix -= block.prefixLength; 906 | } 907 | if (prefix < 0) { // not indented as far as previous point 908 | new = right; 909 | } else { // indented past previous 910 | new = [NSMutableArray arrayWithArray:left]; 911 | [[right firstObject] setPrefixLength:prefix]; 912 | [new addObjectsFromArray:right]; 913 | } 914 | 915 | return new; 916 | } 917 | 918 | - (void)markupRegion:(NSRange) stringRange in:(NSMutableAttributedString *)string withData:(NSArray *)data { 919 | // for (OGRegularExpressionMatch *lineMatch in [[OGRegularExpression regularExpressionWithString:@"[^\\n]*\\n?"] matchEnumeratorInAttributedString:string range:stringRange]) { 920 | int i = 0; 921 | for (MDStack *stackInfo in data) { 922 | NSMutableArray *stack = stackInfo.array; 923 | NSRange range = stackInfo.range; 924 | // NSLog(@"looking at |%@| %@", [[string attributedSubstringFromRange:range] string], stack); 925 | 926 | if ([[stack firstObject] type] == plainType) { // Could be lazily continued paragraph, indent according to previous stack 927 | NSMutableArray *prevStack = [self previousContentStack:data before:i]; 928 | if (prevStack != nil) stack = prevStack; 929 | } else if ([[stack firstObject] type] == indentType) { 930 | NSMutableArray *prevStack = [self previousListStack:data before:i]; 931 | if (prevStack != nil) { 932 | [self popParagraphBlocks:prevStack]; 933 | stack = [self mergeIndentedStack:stack onto:prevStack]; 934 | } else if ([[stack firstObject] prefixLength] >= 4) { 935 | stack = [NSMutableArray arrayWithObject:[MDBlock blockWithType:codeType indent:0 prefix:4 match:[[stack firstObject] match]]]; 936 | } else if ((prevStack = [self previousContentStack:data before:i]) != nil) { 937 | stack = prevStack; 938 | } 939 | } 940 | // NSLog(@"rendering as %@\n----------", stack); 941 | [self markLine:string range:range stack:stack]; 942 | i += 1; 943 | } 944 | 945 | if (newReferences) { 946 | [self markLinks:string range:NSMakeRange(0, [string length])]; 947 | [self markImages:string range:NSMakeRange(0, [string length])]; 948 | newReferences = false; 949 | } 950 | } 951 | 952 | - (void)markupString:(NSMutableAttributedString *)string inRange:(NSRange)range { 953 | // NSLog(@"editing:(\n|%@|\n)", [[string attributedSubstringFromRange:edited] string]); 954 | range = [self expandRangeToParagraph:range forString:string]; 955 | 956 | [string beginEditing]; 957 | [string removeAttribute:NSParagraphStyleAttributeName range:range]; 958 | [string removeAttribute:NSFontAttributeName range:range]; 959 | [string removeAttribute:NSForegroundColorAttributeName range:range]; 960 | [string removeAttribute:NSBackgroundColorAttributeName range:range]; 961 | [string removeAttribute:NSKernAttributeName range:range]; 962 | [string removeAttribute:NSToolTipAttributeName range:range]; 963 | [string removeAttribute:MarkdownCodeSection range:range]; 964 | [string removeAttribute:NSLinkAttributeName range:range]; 965 | [string addAttributes:defaultAttributes range:range]; 966 | 967 | NSArray *parse = [self parseRegion:range in:string]; 968 | // NSLog(@"Parsed to %@\n", parse); 969 | [self markupRegion:range in:string withData:parse]; 970 | 971 | [string fixAttributesInRange:range]; 972 | [string endEditing]; 973 | } 974 | 975 | - (void)markupString:(NSMutableAttributedString *)string { 976 | [self markupString:string inRange:NSMakeRange(0, [string length])]; 977 | } 978 | 979 | - (void)textStorageDidProcessEditing:(NSNotification *)aNotification { 980 | NSTextStorage *storage = [aNotification object]; 981 | NSRange edited = [storage editedRange]; 982 | 983 | [self markupString:storage inRange:edited]; 984 | } 985 | 986 | - (void)makeText:(NSMutableAttributedString *)string size:(int)size { 987 | baseFontSize = size; 988 | if (baseFontSize < 10) baseFontSize = 10; 989 | [self setWidth:[text frame].size.width]; 990 | [self configureTextStyles]; 991 | [self markupString:string]; 992 | } 993 | 994 | - (void)makeTextLarger:(NSMutableAttributedString *)string { 995 | [self makeText:string size:baseFontSize + 2]; 996 | } 997 | 998 | - (void)makeTextSmaller:(NSMutableAttributedString *)string { 999 | [self makeText:string size:baseFontSize - 2]; 1000 | } 1001 | 1002 | - (void)resetTextSize:(NSMutableAttributedString *)string { 1003 | [self makeText:string size:16]; 1004 | } 1005 | 1006 | -(void)setWidth:(CGFloat)width { 1007 | CGFloat inset = (width - 38 * baseFontSize)/2; 1008 | if (inset < 1.5 * baseFontSize) { 1009 | inset = 1.5 * baseFontSize; 1010 | } 1011 | 1012 | NSSize size = {inset, 2 * baseFontSize}; 1013 | [text setTextContainerInset:size]; 1014 | } 1015 | 1016 | // Nicked from http://lists.apple.com/archives/cocoa-dev/2005/Jun/msg01909.html 1017 | - (NSRange)visibleRange { 1018 | NSScrollView *sv = [text enclosingScrollView]; 1019 | if(!sv) return NSMakeRange(0,0); 1020 | NSLayoutManager *lm = [text layoutManager]; 1021 | NSRect visRect = [text visibleRect]; 1022 | 1023 | NSPoint tco = [text textContainerOrigin]; 1024 | visRect.origin.x -= tco.x; 1025 | visRect.origin.y -= tco.y; 1026 | 1027 | NSRange glyphRange = [lm glyphRangeForBoundingRect:visRect inTextContainer:[text textContainer]]; 1028 | NSRange charRange = [lm characterRangeForGlyphRange:glyphRange actualGlyphRange:nil]; 1029 | return charRange; 1030 | } 1031 | 1032 | -(void)recenterOn:(NSRange)range { 1033 | [text scrollRangeToVisible:range]; 1034 | } 1035 | 1036 | // Can't use `textView:willCheckTextInRange:options:types:` as it's 1037 | // range might span across a whole code section, so it's easier to 1038 | // just avoid marking found errors in code sections. 1039 | - (NSInteger)textView:(NSTextView *)textView shouldSetSpellingState:(NSInteger)value range:(NSRange)affectedCharRange { 1040 | // NSLog(@"Setting spelling state of %d on {%d,%d}", value, affectedCharRange.location, affectedCharRange.length); 1041 | if (value != 0 && [self isCodeSection:[textView textStorage] atIndex:affectedCharRange.location]) { 1042 | value = 0; 1043 | } 1044 | return value; 1045 | } 1046 | 1047 | @end 1048 | -------------------------------------------------------------------------------- /English.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1060 5 | 11A511 6 | 1617 7 | 1138 8 | 566.00 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 1617 12 | 13 | 14 | YES 15 | NSMenu 16 | NSMenuItem 17 | NSCustomObject 18 | 19 | 20 | YES 21 | com.apple.InterfaceBuilder.CocoaPlugin 22 | 23 | 24 | YES 25 | 26 | YES 27 | 28 | 29 | 30 | 31 | YES 32 | 33 | NSApplication 34 | 35 | 36 | FirstResponder 37 | 38 | 39 | NSApplication 40 | 41 | 42 | AMainMenu 43 | 44 | YES 45 | 46 | 47 | MarkEdit 48 | 49 | 1048576 50 | 2147483647 51 | 52 | NSImage 53 | NSMenuCheckmark 54 | 55 | 56 | NSImage 57 | NSMenuMixedState 58 | 59 | submenuAction: 60 | 61 | MarkEdit 62 | 63 | YES 64 | 65 | 66 | About MarkEdit 67 | 68 | 2147483647 69 | 70 | 71 | 72 | 73 | 74 | YES 75 | YES 76 | 77 | 78 | 1048576 79 | 2147483647 80 | 81 | 82 | 83 | 84 | 85 | Services 86 | 87 | 1048576 88 | 2147483647 89 | 90 | 91 | submenuAction: 92 | 93 | Services 94 | 95 | YES 96 | 97 | _NSServicesMenu 98 | 99 | 100 | 101 | 102 | YES 103 | YES 104 | 105 | 106 | 1048576 107 | 2147483647 108 | 109 | 110 | 111 | 112 | 113 | Hide MarkEdit 114 | h 115 | 1048576 116 | 2147483647 117 | 118 | 119 | 120 | 121 | 122 | Hide Others 123 | h 124 | 1572864 125 | 2147483647 126 | 127 | 128 | 129 | 130 | 131 | Show All 132 | 133 | 1048576 134 | 2147483647 135 | 136 | 137 | 138 | 139 | 140 | YES 141 | YES 142 | 143 | 144 | 1048576 145 | 2147483647 146 | 147 | 148 | 149 | 150 | 151 | Quit MarkEdit 152 | q 153 | 1048576 154 | 2147483647 155 | 156 | 157 | 158 | 159 | _NSAppleMenu 160 | 161 | 162 | 163 | 164 | File 165 | 166 | 1048576 167 | 2147483647 168 | 169 | 170 | submenuAction: 171 | 172 | File 173 | 174 | YES 175 | 176 | 177 | New 178 | n 179 | 1048576 180 | 2147483647 181 | 182 | 183 | 184 | 185 | 186 | Open… 187 | o 188 | 1048576 189 | 2147483647 190 | 191 | 192 | 193 | 194 | 195 | Open Recent 196 | 197 | 1048576 198 | 2147483647 199 | 200 | 201 | submenuAction: 202 | 203 | Open Recent 204 | 205 | YES 206 | 207 | 208 | Clear Menu 209 | 210 | 1048576 211 | 2147483647 212 | 213 | 214 | 215 | 216 | _NSRecentDocumentsMenu 217 | 218 | 219 | 220 | 221 | YES 222 | YES 223 | 224 | 225 | 1048576 226 | 2147483647 227 | 228 | 229 | 230 | 231 | 232 | Close 233 | w 234 | 1048576 235 | 2147483647 236 | 237 | 238 | 239 | 240 | 241 | Save 242 | s 243 | 1048576 244 | 2147483647 245 | 246 | 247 | 248 | 249 | 250 | Save As… 251 | S 252 | 1179648 253 | 2147483647 254 | 255 | 256 | 257 | 258 | 259 | Revert to Saved 260 | 261 | 2147483647 262 | 263 | 264 | 265 | 266 | 267 | YES 268 | YES 269 | 270 | 271 | 1048576 272 | 2147483647 273 | 274 | 275 | 276 | 277 | 278 | Page Setup... 279 | P 280 | 1179648 281 | 2147483647 282 | 283 | 284 | 285 | 286 | 287 | 288 | Print… 289 | p 290 | 1048576 291 | 2147483647 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | Edit 301 | 302 | 1048576 303 | 2147483647 304 | 305 | 306 | submenuAction: 307 | 308 | Edit 309 | 310 | YES 311 | 312 | 313 | Undo 314 | z 315 | 1048576 316 | 2147483647 317 | 318 | 319 | 320 | 321 | 322 | Redo 323 | Z 324 | 1179648 325 | 2147483647 326 | 327 | 328 | 329 | 330 | 331 | YES 332 | YES 333 | 334 | 335 | 1048576 336 | 2147483647 337 | 338 | 339 | 340 | 341 | 342 | Cut 343 | x 344 | 1048576 345 | 2147483647 346 | 347 | 348 | 349 | 350 | 351 | Copy 352 | c 353 | 1048576 354 | 2147483647 355 | 356 | 357 | 358 | 359 | 360 | Paste 361 | v 362 | 1048576 363 | 2147483647 364 | 365 | 366 | 367 | 368 | 369 | Delete 370 | 371 | 1048576 372 | 2147483647 373 | 374 | 375 | 376 | 377 | 378 | Select All 379 | a 380 | 1048576 381 | 2147483647 382 | 383 | 384 | 385 | 386 | 387 | YES 388 | YES 389 | 390 | 391 | 1048576 392 | 2147483647 393 | 394 | 395 | 396 | 397 | 398 | Find 399 | 400 | 1048576 401 | 2147483647 402 | 403 | 404 | submenuAction: 405 | 406 | Find 407 | 408 | YES 409 | 410 | 411 | Find… 412 | f 413 | 1048576 414 | 2147483647 415 | 416 | 417 | 1 418 | 419 | 420 | 421 | Find Next 422 | g 423 | 1048576 424 | 2147483647 425 | 426 | 427 | 2 428 | 429 | 430 | 431 | Find Previous 432 | G 433 | 1179648 434 | 2147483647 435 | 436 | 437 | 3 438 | 439 | 440 | 441 | Use Selection for Find 442 | e 443 | 1048576 444 | 2147483647 445 | 446 | 447 | 7 448 | 449 | 450 | 451 | Jump to Selection 452 | j 453 | 1048576 454 | 2147483647 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | Spelling and Grammar 464 | 465 | 1048576 466 | 2147483647 467 | 468 | 469 | submenuAction: 470 | 471 | Spelling and Grammar 472 | 473 | YES 474 | 475 | 476 | Show Spelling and Grammar 477 | : 478 | 1048576 479 | 2147483647 480 | 481 | 482 | 483 | 484 | 485 | Check Document Now 486 | ; 487 | 1048576 488 | 2147483647 489 | 490 | 491 | 492 | 493 | 494 | YES 495 | YES 496 | 497 | 498 | 2147483647 499 | 500 | 501 | 502 | 503 | 504 | Check Spelling While Typing 505 | 506 | 1048576 507 | 2147483647 508 | 509 | 510 | 511 | 512 | 513 | Check Grammar With Spelling 514 | 515 | 1048576 516 | 2147483647 517 | 518 | 519 | 520 | 521 | 522 | Correct Spelling Automatically 523 | 524 | 2147483647 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | Substitutions 534 | 535 | 1048576 536 | 2147483647 537 | 538 | 539 | submenuAction: 540 | 541 | Substitutions 542 | 543 | YES 544 | 545 | 546 | Show Substitutions 547 | 548 | 2147483647 549 | 550 | 551 | 552 | 553 | 554 | YES 555 | YES 556 | 557 | 558 | 2147483647 559 | 560 | 561 | 562 | 563 | 564 | Smart Copy/Paste 565 | f 566 | 1048576 567 | 2147483647 568 | 569 | 570 | 1 571 | 572 | 573 | 574 | Smart Quotes 575 | g 576 | 1048576 577 | 2147483647 578 | 579 | 580 | 2 581 | 582 | 583 | 584 | Smart Dashes 585 | 586 | 2147483647 587 | 588 | 589 | 590 | 591 | 592 | Smart Links 593 | G 594 | 1179648 595 | 2147483647 596 | 597 | 598 | 3 599 | 600 | 601 | 602 | Text Replacement 603 | 604 | 2147483647 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | Transformations 614 | 615 | 2147483647 616 | 617 | 618 | submenuAction: 619 | 620 | Transformations 621 | 622 | YES 623 | 624 | 625 | Make Upper Case 626 | 627 | 2147483647 628 | 629 | 630 | 631 | 632 | 633 | Make Lower Case 634 | 635 | 2147483647 636 | 637 | 638 | 639 | 640 | 641 | Capitalize 642 | 643 | 2147483647 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | Speech 653 | 654 | 1048576 655 | 2147483647 656 | 657 | 658 | submenuAction: 659 | 660 | Speech 661 | 662 | YES 663 | 664 | 665 | Start Speaking 666 | 667 | 1048576 668 | 2147483647 669 | 670 | 671 | 672 | 673 | 674 | Stop Speaking 675 | 676 | 1048576 677 | 2147483647 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | View 690 | 691 | 2147483647 692 | 693 | 694 | submenuAction: 695 | 696 | View 697 | 698 | YES 699 | 700 | 701 | Bigger 702 | + 703 | 1048576 704 | 2147483647 705 | 706 | 707 | 3 708 | 709 | 710 | 711 | Smaller 712 | - 713 | 1048576 714 | 2147483647 715 | 716 | 717 | 4 718 | 719 | 720 | 721 | Default Size 722 | 723 | 2147483647 724 | 725 | 726 | 727 | 728 | 729 | Refresh Syntax 730 | r 731 | 1048576 732 | 2147483647 733 | 734 | 735 | 736 | 737 | _NSFontMenu 738 | 739 | 740 | 741 | 742 | Window 743 | 744 | 1048576 745 | 2147483647 746 | 747 | 748 | submenuAction: 749 | 750 | Window 751 | 752 | YES 753 | 754 | 755 | Enter Full Screen 756 | f 757 | 1310720 758 | 2147483647 759 | 760 | 761 | 762 | 763 | 764 | Minimize 765 | m 766 | 1048576 767 | 2147483647 768 | 769 | 770 | 771 | 772 | 773 | Zoom 774 | 775 | 1048576 776 | 2147483647 777 | 778 | 779 | 780 | 781 | 782 | YES 783 | YES 784 | 785 | 786 | 1048576 787 | 2147483647 788 | 789 | 790 | 791 | 792 | 793 | Bring All to Front 794 | 795 | 1048576 796 | 2147483647 797 | 798 | 799 | 800 | 801 | _NSWindowsMenu 802 | 803 | 804 | 805 | 806 | Help 807 | 808 | 2147483647 809 | 810 | 811 | submenuAction: 812 | 813 | Help 814 | 815 | YES 816 | 817 | 818 | MarkEdit Help 819 | ? 820 | 1048576 821 | 2147483647 822 | 823 | 824 | 825 | 826 | _NSHelpMenu 827 | 828 | 829 | 830 | _NSMainMenu 831 | 832 | 833 | NSFontManager 834 | 835 | 836 | 837 | 838 | YES 839 | 840 | 841 | performMiniaturize: 842 | 843 | 844 | 845 | 37 846 | 847 | 848 | 849 | arrangeInFront: 850 | 851 | 852 | 853 | 39 854 | 855 | 856 | 857 | runPageLayout: 858 | 859 | 860 | 861 | 87 862 | 863 | 864 | 865 | clearRecentDocuments: 866 | 867 | 868 | 869 | 127 870 | 871 | 872 | 873 | orderFrontStandardAboutPanel: 874 | 875 | 876 | 877 | 142 878 | 879 | 880 | 881 | performClose: 882 | 883 | 884 | 885 | 193 886 | 887 | 888 | 889 | toggleContinuousSpellChecking: 890 | 891 | 892 | 893 | 222 894 | 895 | 896 | 897 | undo: 898 | 899 | 900 | 901 | 223 902 | 903 | 904 | 905 | copy: 906 | 907 | 908 | 909 | 224 910 | 911 | 912 | 913 | checkSpelling: 914 | 915 | 916 | 917 | 225 918 | 919 | 920 | 921 | paste: 922 | 923 | 924 | 925 | 226 926 | 927 | 928 | 929 | stopSpeaking: 930 | 931 | 932 | 933 | 227 934 | 935 | 936 | 937 | cut: 938 | 939 | 940 | 941 | 228 942 | 943 | 944 | 945 | showGuessPanel: 946 | 947 | 948 | 949 | 230 950 | 951 | 952 | 953 | redo: 954 | 955 | 956 | 957 | 231 958 | 959 | 960 | 961 | selectAll: 962 | 963 | 964 | 965 | 232 966 | 967 | 968 | 969 | startSpeaking: 970 | 971 | 972 | 973 | 233 974 | 975 | 976 | 977 | delete: 978 | 979 | 980 | 981 | 235 982 | 983 | 984 | 985 | performZoom: 986 | 987 | 988 | 989 | 240 990 | 991 | 992 | 993 | performFindPanelAction: 994 | 995 | 996 | 997 | 241 998 | 999 | 1000 | 1001 | centerSelectionInVisibleArea: 1002 | 1003 | 1004 | 1005 | 245 1006 | 1007 | 1008 | 1009 | toggleGrammarChecking: 1010 | 1011 | 1012 | 1013 | 347 1014 | 1015 | 1016 | 1017 | toggleSmartInsertDelete: 1018 | 1019 | 1020 | 1021 | 355 1022 | 1023 | 1024 | 1025 | toggleAutomaticQuoteSubstitution: 1026 | 1027 | 1028 | 1029 | 356 1030 | 1031 | 1032 | 1033 | toggleAutomaticLinkDetection: 1034 | 1035 | 1036 | 1037 | 357 1038 | 1039 | 1040 | 1041 | saveDocument: 1042 | 1043 | 1044 | 1045 | 362 1046 | 1047 | 1048 | 1049 | saveDocumentAs: 1050 | 1051 | 1052 | 1053 | 363 1054 | 1055 | 1056 | 1057 | revertDocumentToSaved: 1058 | 1059 | 1060 | 1061 | 364 1062 | 1063 | 1064 | 1065 | hide: 1066 | 1067 | 1068 | 1069 | 367 1070 | 1071 | 1072 | 1073 | hideOtherApplications: 1074 | 1075 | 1076 | 1077 | 368 1078 | 1079 | 1080 | 1081 | unhideAllApplications: 1082 | 1083 | 1084 | 1085 | 370 1086 | 1087 | 1088 | 1089 | newDocument: 1090 | 1091 | 1092 | 1093 | 371 1094 | 1095 | 1096 | 1097 | openDocument: 1098 | 1099 | 1100 | 1101 | 372 1102 | 1103 | 1104 | 1105 | printDocument: 1106 | 1107 | 1108 | 1109 | 373 1110 | 1111 | 1112 | 1113 | terminate: 1114 | 1115 | 1116 | 1117 | 448 1118 | 1119 | 1120 | 1121 | capitalizeWord: 1122 | 1123 | 1124 | 1125 | 454 1126 | 1127 | 1128 | 1129 | lowercaseWord: 1130 | 1131 | 1132 | 1133 | 455 1134 | 1135 | 1136 | 1137 | uppercaseWord: 1138 | 1139 | 1140 | 1141 | 456 1142 | 1143 | 1144 | 1145 | toggleAutomaticDashSubstitution: 1146 | 1147 | 1148 | 1149 | 460 1150 | 1151 | 1152 | 1153 | orderFrontSubstitutionsPanel: 1154 | 1155 | 1156 | 1157 | 461 1158 | 1159 | 1160 | 1161 | toggleAutomaticTextReplacement: 1162 | 1163 | 1164 | 1165 | 463 1166 | 1167 | 1168 | 1169 | toggleAutomaticSpellingCorrection: 1170 | 1171 | 1172 | 1173 | 466 1174 | 1175 | 1176 | 1177 | performFindPanelAction: 1178 | 1179 | 1180 | 1181 | 467 1182 | 1183 | 1184 | 1185 | performFindPanelAction: 1186 | 1187 | 1188 | 1189 | 468 1190 | 1191 | 1192 | 1193 | performFindPanelAction: 1194 | 1195 | 1196 | 1197 | 469 1198 | 1199 | 1200 | 1201 | showHelp: 1202 | 1203 | 1204 | 1205 | 494 1206 | 1207 | 1208 | 1209 | makeTextLarger: 1210 | 1211 | 1212 | 1213 | 710 1214 | 1215 | 1216 | 1217 | makeTextSmaller: 1218 | 1219 | 1220 | 1221 | 711 1222 | 1223 | 1224 | 1225 | makeTextStandardSize: 1226 | 1227 | 1228 | 1229 | 714 1230 | 1231 | 1232 | 1233 | reload: 1234 | 1235 | 1236 | 1237 | 716 1238 | 1239 | 1240 | 1241 | toggleFullScreen: 1242 | 1243 | 1244 | 1245 | 718 1246 | 1247 | 1248 | 1249 | 1250 | YES 1251 | 1252 | 0 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | -2 1259 | 1260 | 1261 | File's Owner 1262 | 1263 | 1264 | -1 1265 | 1266 | 1267 | First Responder 1268 | 1269 | 1270 | -3 1271 | 1272 | 1273 | Application 1274 | 1275 | 1276 | 29 1277 | 1278 | 1279 | YES 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 19 1291 | 1292 | 1293 | YES 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 56 1300 | 1301 | 1302 | YES 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 217 1309 | 1310 | 1311 | YES 1312 | 1313 | 1314 | 1315 | 1316 | 1317 | 83 1318 | 1319 | 1320 | YES 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 81 1327 | 1328 | 1329 | YES 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | 1336 | 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 75 1346 | 1347 | 1348 | 1349 | 1350 | 80 1351 | 1352 | 1353 | 1354 | 1355 | 78 1356 | 1357 | 1358 | 1359 | 1360 | 72 1361 | 1362 | 1363 | 1364 | 1365 | 82 1366 | 1367 | 1368 | 1369 | 1370 | 124 1371 | 1372 | 1373 | YES 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 77 1380 | 1381 | 1382 | 1383 | 1384 | 73 1385 | 1386 | 1387 | 1388 | 1389 | 79 1390 | 1391 | 1392 | 1393 | 1394 | 112 1395 | 1396 | 1397 | 1398 | 1399 | 74 1400 | 1401 | 1402 | 1403 | 1404 | 125 1405 | 1406 | 1407 | YES 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 126 1414 | 1415 | 1416 | 1417 | 1418 | 205 1419 | 1420 | 1421 | YES 1422 | 1423 | 1424 | 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 | 1436 | 1437 | 1438 | 1439 | 1440 | 202 1441 | 1442 | 1443 | 1444 | 1445 | 198 1446 | 1447 | 1448 | 1449 | 1450 | 207 1451 | 1452 | 1453 | 1454 | 1455 | 214 1456 | 1457 | 1458 | 1459 | 1460 | 199 1461 | 1462 | 1463 | 1464 | 1465 | 203 1466 | 1467 | 1468 | 1469 | 1470 | 197 1471 | 1472 | 1473 | 1474 | 1475 | 206 1476 | 1477 | 1478 | 1479 | 1480 | 215 1481 | 1482 | 1483 | 1484 | 1485 | 218 1486 | 1487 | 1488 | YES 1489 | 1490 | 1491 | 1492 | 1493 | 1494 | 216 1495 | 1496 | 1497 | YES 1498 | 1499 | 1500 | 1501 | 1502 | 1503 | 200 1504 | 1505 | 1506 | YES 1507 | 1508 | 1509 | 1510 | 1511 | 1512 | 1513 | 1514 | 1515 | 1516 | 1517 | 219 1518 | 1519 | 1520 | 1521 | 1522 | 201 1523 | 1524 | 1525 | 1526 | 1527 | 204 1528 | 1529 | 1530 | 1531 | 1532 | 220 1533 | 1534 | 1535 | YES 1536 | 1537 | 1538 | 1539 | 1540 | 1541 | 1542 | 1543 | 1544 | 1545 | 213 1546 | 1547 | 1548 | 1549 | 1550 | 210 1551 | 1552 | 1553 | 1554 | 1555 | 221 1556 | 1557 | 1558 | 1559 | 1560 | 208 1561 | 1562 | 1563 | 1564 | 1565 | 209 1566 | 1567 | 1568 | 1569 | 1570 | 57 1571 | 1572 | 1573 | YES 1574 | 1575 | 1576 | 1577 | 1578 | 1579 | 1580 | 1581 | 1582 | 1583 | 1584 | 1585 | 1586 | 1587 | 58 1588 | 1589 | 1590 | 1591 | 1592 | 134 1593 | 1594 | 1595 | 1596 | 1597 | 150 1598 | 1599 | 1600 | 1601 | 1602 | 136 1603 | 1604 | 1605 | 1606 | 1607 | 144 1608 | 1609 | 1610 | 1611 | 1612 | 143 1613 | 1614 | 1615 | 1616 | 1617 | 131 1618 | 1619 | 1620 | YES 1621 | 1622 | 1623 | 1624 | 1625 | 1626 | 149 1627 | 1628 | 1629 | 1630 | 1631 | 145 1632 | 1633 | 1634 | 1635 | 1636 | 130 1637 | 1638 | 1639 | 1640 | 1641 | 24 1642 | 1643 | 1644 | YES 1645 | 1646 | 1647 | 1648 | 1649 | 1650 | 1651 | 1652 | 1653 | 1654 | 92 1655 | 1656 | 1657 | 1658 | 1659 | 5 1660 | 1661 | 1662 | 1663 | 1664 | 239 1665 | 1666 | 1667 | 1668 | 1669 | 23 1670 | 1671 | 1672 | 1673 | 1674 | 211 1675 | 1676 | 1677 | YES 1678 | 1679 | 1680 | 1681 | 1682 | 1683 | 212 1684 | 1685 | 1686 | YES 1687 | 1688 | 1689 | 1690 | 1691 | 1692 | 1693 | 195 1694 | 1695 | 1696 | 1697 | 1698 | 196 1699 | 1700 | 1701 | 1702 | 1703 | 346 1704 | 1705 | 1706 | 1707 | 1708 | 348 1709 | 1710 | 1711 | YES 1712 | 1713 | 1714 | 1715 | 1716 | 1717 | 349 1718 | 1719 | 1720 | YES 1721 | 1722 | 1723 | 1724 | 1725 | 1726 | 1727 | 1728 | 1729 | 1730 | 1731 | 1732 | 350 1733 | 1734 | 1735 | 1736 | 1737 | 351 1738 | 1739 | 1740 | 1741 | 1742 | 354 1743 | 1744 | 1745 | 1746 | 1747 | 419 1748 | 1749 | 1750 | 1751 | 1752 | 449 1753 | 1754 | 1755 | YES 1756 | 1757 | 1758 | 1759 | 1760 | 1761 | 450 1762 | 1763 | 1764 | YES 1765 | 1766 | 1767 | 1768 | 1769 | 1770 | 1771 | 1772 | 451 1773 | 1774 | 1775 | 1776 | 1777 | 452 1778 | 1779 | 1780 | 1781 | 1782 | 453 1783 | 1784 | 1785 | 1786 | 1787 | 457 1788 | 1789 | 1790 | 1791 | 1792 | 458 1793 | 1794 | 1795 | 1796 | 1797 | 459 1798 | 1799 | 1800 | 1801 | 1802 | 462 1803 | 1804 | 1805 | 1806 | 1807 | 464 1808 | 1809 | 1810 | 1811 | 1812 | 465 1813 | 1814 | 1815 | 1816 | 1817 | 491 1818 | 1819 | 1820 | YES 1821 | 1822 | 1823 | 1824 | 1825 | 1826 | 492 1827 | 1828 | 1829 | YES 1830 | 1831 | 1832 | 1833 | 1834 | 1835 | 493 1836 | 1837 | 1838 | 1839 | 1840 | 656 1841 | 1842 | 1843 | YES 1844 | 1845 | 1846 | 1847 | 1848 | 1849 | 657 1850 | 1851 | 1852 | YES 1853 | 1854 | 1855 | 1856 | 1857 | 1858 | 1859 | 1860 | 1861 | 663 1862 | 1863 | 1864 | 1865 | 1866 | 664 1867 | 1868 | 1869 | 1870 | 1871 | 713 1872 | 1873 | 1874 | 1875 | 1876 | 715 1877 | 1878 | 1879 | 1880 | 1881 | 717 1882 | 1883 | 1884 | 1885 | 1886 | 1887 | 1888 | YES 1889 | 1890 | YES 1891 | -1.IBPluginDependency 1892 | -2.IBPluginDependency 1893 | -3.IBPluginDependency 1894 | 112.IBPluginDependency 1895 | 124.IBPluginDependency 1896 | 125.IBPluginDependency 1897 | 126.IBPluginDependency 1898 | 130.IBPluginDependency 1899 | 131.IBPluginDependency 1900 | 134.IBPluginDependency 1901 | 136.IBPluginDependency 1902 | 143.IBPluginDependency 1903 | 144.IBPluginDependency 1904 | 145.IBPluginDependency 1905 | 149.IBPluginDependency 1906 | 150.IBPluginDependency 1907 | 19.IBPluginDependency 1908 | 195.IBPluginDependency 1909 | 196.IBPluginDependency 1910 | 197.IBPluginDependency 1911 | 198.IBPluginDependency 1912 | 199.IBPluginDependency 1913 | 200.IBPluginDependency 1914 | 201.IBPluginDependency 1915 | 202.IBPluginDependency 1916 | 203.IBPluginDependency 1917 | 204.IBPluginDependency 1918 | 205.IBPluginDependency 1919 | 206.IBPluginDependency 1920 | 207.IBPluginDependency 1921 | 208.IBPluginDependency 1922 | 209.IBPluginDependency 1923 | 210.IBPluginDependency 1924 | 211.IBPluginDependency 1925 | 212.IBPluginDependency 1926 | 213.IBPluginDependency 1927 | 214.IBPluginDependency 1928 | 215.IBPluginDependency 1929 | 216.IBPluginDependency 1930 | 217.IBPluginDependency 1931 | 218.IBPluginDependency 1932 | 219.IBPluginDependency 1933 | 220.IBPluginDependency 1934 | 221.IBPluginDependency 1935 | 23.IBPluginDependency 1936 | 239.IBPluginDependency 1937 | 24.IBPluginDependency 1938 | 29.IBPluginDependency 1939 | 346.IBPluginDependency 1940 | 348.IBPluginDependency 1941 | 349.IBPluginDependency 1942 | 350.IBPluginDependency 1943 | 351.IBPluginDependency 1944 | 354.IBPluginDependency 1945 | 419.IBPluginDependency 1946 | 449.IBPluginDependency 1947 | 450.IBPluginDependency 1948 | 451.IBPluginDependency 1949 | 452.IBPluginDependency 1950 | 453.IBPluginDependency 1951 | 457.IBPluginDependency 1952 | 458.IBPluginDependency 1953 | 459.IBPluginDependency 1954 | 462.IBPluginDependency 1955 | 464.IBPluginDependency 1956 | 465.IBPluginDependency 1957 | 491.IBPluginDependency 1958 | 492.IBPluginDependency 1959 | 493.IBPluginDependency 1960 | 5.IBPluginDependency 1961 | 56.IBPluginDependency 1962 | 57.IBPluginDependency 1963 | 58.IBPluginDependency 1964 | 656.IBPluginDependency 1965 | 657.IBPluginDependency 1966 | 663.IBPluginDependency 1967 | 664.IBPluginDependency 1968 | 713.IBPluginDependency 1969 | 715.IBPluginDependency 1970 | 717.IBPluginDependency 1971 | 72.IBPluginDependency 1972 | 73.IBPluginDependency 1973 | 74.IBPluginDependency 1974 | 75.IBPluginDependency 1975 | 77.IBPluginDependency 1976 | 78.IBPluginDependency 1977 | 79.IBPluginDependency 1978 | 80.IBPluginDependency 1979 | 81.IBPluginDependency 1980 | 82.IBPluginDependency 1981 | 83.IBPluginDependency 1982 | 92.IBPluginDependency 1983 | 1984 | 1985 | YES 1986 | com.apple.InterfaceBuilder.CocoaPlugin 1987 | com.apple.InterfaceBuilder.CocoaPlugin 1988 | com.apple.InterfaceBuilder.CocoaPlugin 1989 | com.apple.InterfaceBuilder.CocoaPlugin 1990 | com.apple.InterfaceBuilder.CocoaPlugin 1991 | com.apple.InterfaceBuilder.CocoaPlugin 1992 | com.apple.InterfaceBuilder.CocoaPlugin 1993 | com.apple.InterfaceBuilder.CocoaPlugin 1994 | com.apple.InterfaceBuilder.CocoaPlugin 1995 | com.apple.InterfaceBuilder.CocoaPlugin 1996 | com.apple.InterfaceBuilder.CocoaPlugin 1997 | com.apple.InterfaceBuilder.CocoaPlugin 1998 | com.apple.InterfaceBuilder.CocoaPlugin 1999 | com.apple.InterfaceBuilder.CocoaPlugin 2000 | com.apple.InterfaceBuilder.CocoaPlugin 2001 | com.apple.InterfaceBuilder.CocoaPlugin 2002 | com.apple.InterfaceBuilder.CocoaPlugin 2003 | com.apple.InterfaceBuilder.CocoaPlugin 2004 | com.apple.InterfaceBuilder.CocoaPlugin 2005 | com.apple.InterfaceBuilder.CocoaPlugin 2006 | com.apple.InterfaceBuilder.CocoaPlugin 2007 | com.apple.InterfaceBuilder.CocoaPlugin 2008 | com.apple.InterfaceBuilder.CocoaPlugin 2009 | com.apple.InterfaceBuilder.CocoaPlugin 2010 | com.apple.InterfaceBuilder.CocoaPlugin 2011 | com.apple.InterfaceBuilder.CocoaPlugin 2012 | com.apple.InterfaceBuilder.CocoaPlugin 2013 | com.apple.InterfaceBuilder.CocoaPlugin 2014 | com.apple.InterfaceBuilder.CocoaPlugin 2015 | com.apple.InterfaceBuilder.CocoaPlugin 2016 | com.apple.InterfaceBuilder.CocoaPlugin 2017 | com.apple.InterfaceBuilder.CocoaPlugin 2018 | com.apple.InterfaceBuilder.CocoaPlugin 2019 | com.apple.InterfaceBuilder.CocoaPlugin 2020 | com.apple.InterfaceBuilder.CocoaPlugin 2021 | com.apple.InterfaceBuilder.CocoaPlugin 2022 | com.apple.InterfaceBuilder.CocoaPlugin 2023 | com.apple.InterfaceBuilder.CocoaPlugin 2024 | com.apple.InterfaceBuilder.CocoaPlugin 2025 | com.apple.InterfaceBuilder.CocoaPlugin 2026 | com.apple.InterfaceBuilder.CocoaPlugin 2027 | com.apple.InterfaceBuilder.CocoaPlugin 2028 | com.apple.InterfaceBuilder.CocoaPlugin 2029 | com.apple.InterfaceBuilder.CocoaPlugin 2030 | com.apple.InterfaceBuilder.CocoaPlugin 2031 | com.apple.InterfaceBuilder.CocoaPlugin 2032 | com.apple.InterfaceBuilder.CocoaPlugin 2033 | com.apple.InterfaceBuilder.CocoaPlugin 2034 | com.apple.InterfaceBuilder.CocoaPlugin 2035 | com.apple.InterfaceBuilder.CocoaPlugin 2036 | com.apple.InterfaceBuilder.CocoaPlugin 2037 | com.apple.InterfaceBuilder.CocoaPlugin 2038 | com.apple.InterfaceBuilder.CocoaPlugin 2039 | com.apple.InterfaceBuilder.CocoaPlugin 2040 | com.apple.InterfaceBuilder.CocoaPlugin 2041 | com.apple.InterfaceBuilder.CocoaPlugin 2042 | com.apple.InterfaceBuilder.CocoaPlugin 2043 | com.apple.InterfaceBuilder.CocoaPlugin 2044 | com.apple.InterfaceBuilder.CocoaPlugin 2045 | com.apple.InterfaceBuilder.CocoaPlugin 2046 | com.apple.InterfaceBuilder.CocoaPlugin 2047 | com.apple.InterfaceBuilder.CocoaPlugin 2048 | com.apple.InterfaceBuilder.CocoaPlugin 2049 | com.apple.InterfaceBuilder.CocoaPlugin 2050 | com.apple.InterfaceBuilder.CocoaPlugin 2051 | com.apple.InterfaceBuilder.CocoaPlugin 2052 | com.apple.InterfaceBuilder.CocoaPlugin 2053 | com.apple.InterfaceBuilder.CocoaPlugin 2054 | com.apple.InterfaceBuilder.CocoaPlugin 2055 | com.apple.InterfaceBuilder.CocoaPlugin 2056 | com.apple.InterfaceBuilder.CocoaPlugin 2057 | com.apple.InterfaceBuilder.CocoaPlugin 2058 | com.apple.InterfaceBuilder.CocoaPlugin 2059 | com.apple.InterfaceBuilder.CocoaPlugin 2060 | com.apple.InterfaceBuilder.CocoaPlugin 2061 | com.apple.InterfaceBuilder.CocoaPlugin 2062 | com.apple.InterfaceBuilder.CocoaPlugin 2063 | com.apple.InterfaceBuilder.CocoaPlugin 2064 | com.apple.InterfaceBuilder.CocoaPlugin 2065 | com.apple.InterfaceBuilder.CocoaPlugin 2066 | com.apple.InterfaceBuilder.CocoaPlugin 2067 | com.apple.InterfaceBuilder.CocoaPlugin 2068 | com.apple.InterfaceBuilder.CocoaPlugin 2069 | com.apple.InterfaceBuilder.CocoaPlugin 2070 | com.apple.InterfaceBuilder.CocoaPlugin 2071 | com.apple.InterfaceBuilder.CocoaPlugin 2072 | com.apple.InterfaceBuilder.CocoaPlugin 2073 | com.apple.InterfaceBuilder.CocoaPlugin 2074 | com.apple.InterfaceBuilder.CocoaPlugin 2075 | com.apple.InterfaceBuilder.CocoaPlugin 2076 | com.apple.InterfaceBuilder.CocoaPlugin 2077 | com.apple.InterfaceBuilder.CocoaPlugin 2078 | 2079 | 2080 | 2081 | YES 2082 | 2083 | 2084 | 2085 | 2086 | 2087 | YES 2088 | 2089 | 2090 | 2091 | 2092 | 718 2093 | 2094 | 2095 | 2096 | YES 2097 | 2098 | NSDocument 2099 | 2100 | YES 2101 | 2102 | YES 2103 | printDocument: 2104 | revertDocumentToSaved: 2105 | runPageLayout: 2106 | saveDocument: 2107 | saveDocumentAs: 2108 | saveDocumentTo: 2109 | 2110 | 2111 | YES 2112 | id 2113 | id 2114 | id 2115 | id 2116 | id 2117 | id 2118 | 2119 | 2120 | 2121 | YES 2122 | 2123 | YES 2124 | printDocument: 2125 | revertDocumentToSaved: 2126 | runPageLayout: 2127 | saveDocument: 2128 | saveDocumentAs: 2129 | saveDocumentTo: 2130 | 2131 | 2132 | YES 2133 | 2134 | printDocument: 2135 | id 2136 | 2137 | 2138 | revertDocumentToSaved: 2139 | id 2140 | 2141 | 2142 | runPageLayout: 2143 | id 2144 | 2145 | 2146 | saveDocument: 2147 | id 2148 | 2149 | 2150 | saveDocumentAs: 2151 | id 2152 | 2153 | 2154 | saveDocumentTo: 2155 | id 2156 | 2157 | 2158 | 2159 | 2160 | IBProjectSource 2161 | ./Classes/NSDocument.h 2162 | 2163 | 2164 | 2165 | 2166 | 0 2167 | IBCocoaFramework 2168 | 2169 | com.apple.InterfaceBuilder.CocoaPlugin.macosx 2170 | 2171 | 2172 | 2173 | com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 2174 | 2175 | 2176 | YES 2177 | 3 2178 | 2179 | YES 2180 | 2181 | YES 2182 | NSMenuCheckmark 2183 | NSMenuMixedState 2184 | 2185 | 2186 | YES 2187 | {9, 8} 2188 | {7, 2} 2189 | 2190 | 2191 | 2192 | 2193 | --------------------------------------------------------------------------------