From c832045183322fade004f59cf4bec9ef6573f178 Mon Sep 17 00:00:00 2001 From: 1024jp <1024jp@wolfrosch.com> Date: Fri, 7 Aug 2015 13:18:50 +0900 Subject: [PATCH] Add a feature saving text orientation state to file --- CHANGELOG.md | 2 ++ CotEditor/Sources/CEAppDelegate.m | 1 + CotEditor/Sources/CEDocument.m | 17 +++++++++++- CotEditor/Sources/Constants.h | 1 + CotEditor/Sources/Constants.m | 1 + CotEditor/Sources/NSURL+Xattr.h | 9 +++++++ CotEditor/Sources/NSURL+Xattr.m | 44 +++++++++++++++++++++++++++++-- 7 files changed, 72 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0964bc1b8..6cb98ce78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ develop - CotEditor is now __Sandboxed__. - New setting option for the behavior on document modification by external process (in Genearal pane). - Share button in toolbar (Customize toobar to use it). +- Save text orientation state to the file and restore it when the file is opened. + - __for advanced users__: In this feature, CotEditor saves an *extended attribute* which named `com.coteditor.VerticalText` to the file only when the editor's text orientation is vertical. You can even disable the feature running the command `defaults write com.coteditor.CotEditor savesTextOrientation -bool NO` in Terminal. ### Additions/Changes diff --git a/CotEditor/Sources/CEAppDelegate.m b/CotEditor/Sources/CEAppDelegate.m index 87e4446c0..eaac85f07 100644 --- a/CotEditor/Sources/CEAppDelegate.m +++ b/CotEditor/Sources/CEAppDelegate.m @@ -221,6 +221,7 @@ CEDefaultLargeFileAlertThresholdKey: @(100 * pow(1024, 2)), // 100 MB CEDefaultAutosavingDelayKey: @5.0, CEDefaultEnablesAutosaveInPlaceKey: @NO, + CEDefaultSavesTextOrientationKey: @YES, }; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; diff --git a/CotEditor/Sources/CEDocument.m b/CotEditor/Sources/CEDocument.m index 4eb15472e..320c2cbee 100644 --- a/CotEditor/Sources/CEDocument.m +++ b/CotEditor/Sources/CEDocument.m @@ -65,6 +65,7 @@ NSString *const CEIncompatibleConvertedCharKey = @"convertedChar"; @property (nonatomic) BOOL didAlertNotWritable; // 文書が読み込み専用のときにその警告を表示したかどうか @property (nonatomic, copy) NSString *fileMD5; @property (nonatomic, copy) NSString *fileContentString; // string that is read from the document file +@property (nonatomic, getter=isVerticalText) BOOL verticalText; @property (nonatomic) CEODBEventSender *ODBEventSender; @property (nonatomic) BOOL shouldSaveXattr; @property (nonatomic, copy) NSString *autosaveIdentifier; @@ -156,6 +157,11 @@ NSString *const CEIncompatibleConvertedCharKey = @"convertedChar"; NSNumber *isWritable = nil; [url getResourceValue:&isWritable forKey:NSURLIsWritableKey error:nil]; _writable = [isWritable boolValue]; + + // check file meta data for text orientation + if ([[NSUserDefaults standardUserDefaults] boolForKey:CEDefaultSavesTextOrientationKey]) { + _verticalText = [url getXattrBoolForName:XATTR_VERTICAL_TEXT_NAME]; + } } return self; } @@ -318,8 +324,9 @@ NSString *const CEIncompatibleConvertedCharKey = @"convertedChar"; { // [caution] This method may be called from a background thread due to async-saving. - // store current encoding here, since the main thread will already be unblocked after `dataOfType:error:` + // store current state here, since the main thread will already be unblocked after `dataOfType:error:` NSStringEncoding encoding = [self encoding]; + BOOL isVerticalText = [[self editor] isVerticalLayoutOrientation]; BOOL success = [super writeToURL:url ofType:typeName forSaveOperation:saveOperation originalContentsURL:absoluteOriginalContentsURL error:outError]; @@ -329,6 +336,11 @@ NSString *const CEIncompatibleConvertedCharKey = @"convertedChar"; [url setXattrEncoding:encoding]; } + // save text orientation state + if ([[NSUserDefaults standardUserDefaults] boolForKey:CEDefaultSavesTextOrientationKey]) { + [url setXattrBool:isVerticalText forName:XATTR_VERTICAL_TEXT_NAME]; + } + if (saveOperation != NSAutosaveElsewhereOperation) { // store file hash (MD5) in order to check the file content identity in `presentedItemDidChange` NSData *data = [NSData dataWithContentsOfURL:url]; @@ -741,6 +753,9 @@ NSString *const CEIncompatibleConvertedCharKey = @"convertedChar"; // update line endings menu selection in toolbar [self applyLineEndingToView]; + // apply text orientation + [[self editor] setVerticalLayoutOrientation:[self isVerticalText]]; + // update encoding menu selection in toolbar, status bar and document inspector [self updateEncodingInToolbarAndInfo]; diff --git a/CotEditor/Sources/Constants.h b/CotEditor/Sources/Constants.h index 3b309d0a5..e1ee0ec08 100644 --- a/CotEditor/Sources/Constants.h +++ b/CotEditor/Sources/Constants.h @@ -240,6 +240,7 @@ extern NSString *__nonnull const CEDefaultColoringRangeBufferLengthKey; extern NSString *__nonnull const CEDefaultLargeFileAlertThresholdKey; extern NSString *__nonnull const CEDefaultAutosavingDelayKey; extern NSString *__nonnull const CEDefaultEnablesAutosaveInPlaceKey; +extern NSString *__nonnull const CEDefaultSavesTextOrientationKey; diff --git a/CotEditor/Sources/Constants.m b/CotEditor/Sources/Constants.m index 7c423cb67..3f99068af 100644 --- a/CotEditor/Sources/Constants.m +++ b/CotEditor/Sources/Constants.m @@ -239,6 +239,7 @@ NSString *__nonnull const CEDefaultColoringRangeBufferLengthKey = @"coloringRang NSString *__nonnull const CEDefaultLargeFileAlertThresholdKey = @"largeFileAlertThreshold"; NSString *__nonnull const CEDefaultAutosavingDelayKey = @"autosavingDelay"; NSString *__nonnull const CEDefaultEnablesAutosaveInPlaceKey = @"enablesAutosaveInPlace"; +NSString *__nonnull const CEDefaultSavesTextOrientationKey = @"savesTextOrientation"; diff --git a/CotEditor/Sources/NSURL+Xattr.h b/CotEditor/Sources/NSURL+Xattr.h index 9199b0a39..c7b90cc95 100644 --- a/CotEditor/Sources/NSURL+Xattr.h +++ b/CotEditor/Sources/NSURL+Xattr.h @@ -28,9 +28,18 @@ @import Foundation; +// xattr names +extern char const XATTR_VERTICAL_TEXT_NAME[]; + + @interface NSURL (Xattr) +// for com.apple.TextEncoding - (NSStringEncoding)getXattrEncoding; - (BOOL)setXattrEncoding:(NSStringEncoding)encoding; +// for general bool values +- (BOOL)getXattrBoolForName:(const char *)name; +- (BOOL)setXattrBool:(BOOL)value forName:(const char *)name; + @end diff --git a/CotEditor/Sources/NSURL+Xattr.m b/CotEditor/Sources/NSURL+Xattr.m index 9d73a881b..ecf38adce 100644 --- a/CotEditor/Sources/NSURL+Xattr.m +++ b/CotEditor/Sources/NSURL+Xattr.m @@ -30,6 +30,10 @@ // constants +// public +char const XATTR_VERTICAL_TEXT_NAME[] = "com.coteditor.VerticalText"; + +// private static char const XATTR_ENCODING_NAME[] = "com.apple.TextEncoding"; @@ -77,7 +81,34 @@ static char const XATTR_ENCODING_NAME[] = "com.apple.TextEncoding"; if (!data) { return NO; } - return [self setXattrData:data name:XATTR_ENCODING_NAME]; + return [self setXattrData:data forName:XATTR_ENCODING_NAME]; +} + + + +// ------------------------------------------------------ +/// get boolean value of extended attribute for given name from the file at URL +- (BOOL)getXattrBoolForName:(const char *)name +// ------------------------------------------------------ +{ + NSData *data = [self getXattrDataForName:name]; + + return data != nil; // just check the existance of the key +} + + +// ------------------------------------------------------ +/// set boolean value as extended attribute for given name to the file at URL +- (BOOL)setXattrBool:(BOOL)value forName:(const char *)name +// ------------------------------------------------------ +{ + if (value) { + NSData *data = [NSData dataWithBytes:"1" length:1]; + + return [self setXattrData:data forName:name]; + } else { + return [self removeXattrDataForName:name]; + } } @@ -105,7 +136,7 @@ static char const XATTR_ENCODING_NAME[] = "com.apple.TextEncoding"; // ------------------------------------------------------ /// set extended attribute for given name to the file at URL -- (BOOL)setXattrData:(nonnull NSData *)data name:(const char *)name +- (BOOL)setXattrData:(nonnull NSData *)data forName:(const char *)name // ------------------------------------------------------ { int result = setxattr([[self path] fileSystemRepresentation], name, [data bytes], [data length], 0, XATTR_NOFOLLOW); @@ -113,4 +144,13 @@ static char const XATTR_ENCODING_NAME[] = "com.apple.TextEncoding"; return result == 0; } + +// ------------------------------------------------------ +/// remove extended attribute for given name from the file at URL +- (BOOL)removeXattrDataForName:(const char *)name +// ------------------------------------------------------ +{ + return removexattr([[self path] fileSystemRepresentation], name, XATTR_NOFOLLOW); +} + @end