diff --git a/CHANGELOG.md b/CHANGELOG.md index 8453818fd..4bb027b11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ develop ### New Features +- Now, the execute permission can be given to the file to save from the save panel. - Add “Trim Trailing Whitespace” action to “Text” menu. - Add option to trim trailing whitespace automatically on save (in “General” pane). diff --git a/CotEditor/Base.lproj/SaveDocumentAccessory.xib b/CotEditor/Base.lproj/SaveDocumentAccessory.xib new file mode 100644 index 000000000..03388e2ee --- /dev/null +++ b/CotEditor/Base.lproj/SaveDocumentAccessory.xib @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CotEditor/CotEditor.xcodeproj/project.pbxproj b/CotEditor/CotEditor.xcodeproj/project.pbxproj index a8b339156..e5459c666 100644 --- a/CotEditor/CotEditor.xcodeproj/project.pbxproj +++ b/CotEditor/CotEditor.xcodeproj/project.pbxproj @@ -85,6 +85,8 @@ 2A3A75AB19E77E87001DAB88 /* SyntaxOutlineEditView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A3A75A219E77E87001DAB88 /* SyntaxOutlineEditView.xib */; }; 2A3A75AC19E77E87001DAB88 /* SyntaxValidationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A3A75A419E77E87001DAB88 /* SyntaxValidationView.xib */; }; 2A3A75B319E77F32001DAB88 /* CESyntaxValidationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A3A75B219E77F32001DAB88 /* CESyntaxValidationViewController.m */; }; + 2A3CC1F71C8B442600506DB8 /* SaveDocumentAccessory.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A3CC1F51C8B442600506DB8 /* SaveDocumentAccessory.xib */; }; + 2A3CC1F81C8B442600506DB8 /* SaveDocumentAccessory.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A3CC1F51C8B442600506DB8 /* SaveDocumentAccessory.xib */; }; 2A3FB2AD18ECEFF200D9CB2C /* CESyntaxEditSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A3FB2AC18ECEFF200D9CB2C /* CESyntaxEditSheetController.m */; }; 2A41CB3D1C3906BA00F9122B /* CEInvisibles.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A41CB3C1C3906BA00F9122B /* CEInvisibles.m */; }; 2A41CB3E1C3906BA00F9122B /* CEInvisibles.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A41CB3C1C3906BA00F9122B /* CEInvisibles.m */; }; @@ -568,6 +570,10 @@ 2A3A759319E77D66001DAB88 /* CEMigrationWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CEMigrationWindowController.m; sourceTree = ""; }; 2A3A75B119E77F32001DAB88 /* CESyntaxValidationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CESyntaxValidationViewController.h; sourceTree = ""; }; 2A3A75B219E77F32001DAB88 /* CESyntaxValidationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CESyntaxValidationViewController.m; sourceTree = ""; }; + 2A3CC1F61C8B442600506DB8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SaveDocumentAccessory.xib; sourceTree = ""; }; + 2A3CC1FA1C8B59EB00506DB8 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/SaveDocumentAccessory.strings; sourceTree = ""; }; + 2A3CC1FC1C8B59EE00506DB8 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/SaveDocumentAccessory.strings"; sourceTree = ""; }; + 2A3CC1FE1C8B59F100506DB8 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/SaveDocumentAccessory.strings; sourceTree = ""; }; 2A3FB2AB18ECEFF200D9CB2C /* CESyntaxEditSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CESyntaxEditSheetController.h; sourceTree = ""; }; 2A3FB2AC18ECEFF200D9CB2C /* CESyntaxEditSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CESyntaxEditSheetController.m; sourceTree = ""; }; 2A4063FA1B9DA6080032AC7F /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/SyntaxValidationView.strings; sourceTree = ""; }; @@ -1597,6 +1603,7 @@ isa = PBXGroup; children = ( 2AFFB72A18D8C7DE00118477 /* OpenDocumentAccessory.xib */, + 2A3CC1F51C8B442600506DB8 /* SaveDocumentAccessory.xib */, 2A07202C18E0E421006F3A43 /* PrintPanelAccessory.xib */, 2588E9CC07C4851C0060021D /* ProgressSheet.xib */, 2AB4326C1912ADAC00835004 /* CharacterPopover.xib */, @@ -1906,6 +1913,7 @@ 2A6F0D931B5500E100C2D03C /* NaviBar_Show.tiff in Resources */, 2A6F0D941B5500E100C2D03C /* LineNumber_Hide.tiff in Resources */, 2A6F0D951B5500E100C2D03C /* LineNumber_Show.tiff in Resources */, + 2A3CC1F81C8B442600506DB8 /* SaveDocumentAccessory.xib in Resources */, 2A5DBE591B5D2DB400F8CB13 /* SyntaxOutlineEditView.xib in Resources */, 2A6F0D961B5500E100C2D03C /* StatusBar_Hide.tiff in Resources */, 2A6F0D971B5500E100C2D03C /* StatusBar_Show.tiff in Resources */, @@ -2000,6 +2008,7 @@ 2A961C5418FC699E002076B6 /* ScriptMenu Folder.rtf in Resources */, 2A961C5218FC699E002076B6 /* AppleScript.rtf in Resources */, 2A42825518FCD47B00386899 /* Acknowledgements.rtf in Resources */, + 2A3CC1F71C8B442600506DB8 /* SaveDocumentAccessory.xib in Resources */, 8C081B4B07D0A85A0060191A /* GetInfo.tiff in Resources */, 8C98366708C0211D00746F92 /* IncompatibleChars.tiff in Resources */, 8CA71BCE07D2A79100C146B0 /* BiggerFont.tiff in Resources */, @@ -2705,6 +2714,17 @@ name = SyntaxValidationView.xib; sourceTree = ""; }; + 2A3CC1F51C8B442600506DB8 /* SaveDocumentAccessory.xib */ = { + isa = PBXVariantGroup; + children = ( + 2A3CC1F61C8B442600506DB8 /* Base */, + 2A3CC1FA1C8B59EB00506DB8 /* ja */, + 2A3CC1FC1C8B59EE00506DB8 /* zh-Hans */, + 2A3CC1FE1C8B59F100506DB8 /* de */, + ); + name = SaveDocumentAccessory.xib; + sourceTree = ""; + }; 2A436DCB1A4243D500275FD4 /* DocumentInspectorView.xib */ = { isa = PBXVariantGroup; children = ( diff --git a/CotEditor/Sources/CEDocument.m b/CotEditor/Sources/CEDocument.m index c97984854..1cef8da25 100644 --- a/CotEditor/Sources/CEDocument.m +++ b/CotEditor/Sources/CEDocument.m @@ -73,6 +73,7 @@ NSString *_Nonnull const CEIncompatibleConvertedCharKey = @"convertedChar"; @interface CEDocument () @property (nonatomic, nullable) CEPrintPanelAccessoryController *printPanelAccessoryController; +@property (nonatomic, nullable) IBOutlet NSView *savePanelAccessoryView; @property (nonatomic) NSStringEncoding readingEncoding; // encoding to read document file @property (nonatomic) BOOL needsShowUpdateAlertWithBecomeKey; @@ -85,6 +86,7 @@ NSString *_Nonnull const CEIncompatibleConvertedCharKey = @"convertedChar"; @property (nonatomic) BOOL shouldSaveXattr; @property (nonatomic, nonnull, copy) NSString *autosaveIdentifier; @property (nonatomic) BOOL suppressesIANACharsetConflictAlert; +@property (nonatomic, getter=isExecutable) BOOL executable; // readonly @property (readwrite, nonatomic, nullable) CEWindowController *windowController; @@ -215,6 +217,7 @@ NSString *_Nonnull const CEIncompatibleConvertedCharKey = @"convertedChar"; if ([self fileURL]) { NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[[self fileURL] path] error:outError]; [self setFileAttributes:attributes]; + [self setExecutable:([attributes filePosixPermissions] & S_IXUSR) != 0]; } // try reading the `com.apple.TextEncoding` extended attribute @@ -432,6 +435,30 @@ NSString *_Nonnull const CEIncompatibleConvertedCharKey = @"convertedChar"; } +// ------------------------------------------------------ +/// customize document's file attributes +- (nullable NSDictionary *)fileAttributesToWriteToURL:(nonnull NSURL *)url ofType:(nonnull NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(nullable NSURL *)absoluteOriginalContentsURL error:(NSError * _Nullable __autoreleasing *)outError +// ------------------------------------------------------ +{ + NSMutableDictionary *attributes = [[super fileAttributesToWriteToURL:url ofType:typeName forSaveOperation:saveOperation originalContentsURL:absoluteOriginalContentsURL error:outError] ?: @{} mutableCopy]; + + // give the execute permission if user requested + if ([self isExecutable] && saveOperation != NSAutosaveElsewhereOperation) { + NSUInteger permissions = [attributes filePosixPermissions]; + if (permissions == 0) { + if (absoluteOriginalContentsURL) { // read from old one if not exists + permissions = [[[NSFileManager defaultManager] attributesOfItemAtPath:[absoluteOriginalContentsURL path] error:outError] filePosixPermissions]; + } else { + permissions = 0644; // ???: Is the default permission really always 644? + } + } + attributes[NSFilePosixPermissions] = @(permissions | S_IXUSR); + } + + return [attributes copy]; +} + + // ------------------------------------------------------ /// セーブパネルへ標準のアクセサリビュー(ポップアップメニューでの書類の切り替え)を追加しない - (BOOL)shouldRunSavePanelWithAccessoryView @@ -455,6 +482,12 @@ NSString *_Nonnull const CEIncompatibleConvertedCharKey = @"convertedChar"; [savePanel setExtensionHidden:NO]; [savePanel setCanSelectHiddenExtension:NO]; + // set accessory view + if (![self savePanelAccessoryView]) { + [[NSBundle mainBundle] loadNibNamed:@"SaveDocumentAccessory" owner:self topLevelObjects:nil]; + } + [savePanel setAccessoryView:[self savePanelAccessoryView]]; + // append file extension as a part of the file name // -> NSSaveAsOperation will remove the current file extension from file name in the nameField // as we set nil to `setAllowedFileTypes:` just above. diff --git a/CotEditor/de.lproj/SaveDocumentAccessory.strings b/CotEditor/de.lproj/SaveDocumentAccessory.strings new file mode 100644 index 000000000..61f66b85f --- /dev/null +++ b/CotEditor/de.lproj/SaveDocumentAccessory.strings @@ -0,0 +1,29 @@ +/* + + SaveDocumentAccessory.strings (German) + + CotEditor + http://coteditor.com + + Created by 1024jp on 2016-03-06. + + ------------------------------------------------------------------------------ + + © 2016 CotEditor Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +/* Class = "NSButtonCell"; title = "Give execute permission"; ObjectID = "KjO-BV-esE"; */ +"KjO-BV-esE.title" = "Ausführungsrecht geben"; diff --git a/CotEditor/ja.lproj/SaveDocumentAccessory.strings b/CotEditor/ja.lproj/SaveDocumentAccessory.strings new file mode 100644 index 000000000..ef2790038 --- /dev/null +++ b/CotEditor/ja.lproj/SaveDocumentAccessory.strings @@ -0,0 +1,29 @@ +/* + + SaveDocumentAccessory.strings (Japanese) + + CotEditor + http://coteditor.com + + Created by 1024jp on 2016-03-06. + + ------------------------------------------------------------------------------ + + © 2016 CotEditor Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +/* Class = "NSButtonCell"; title = "Give execute permission"; ObjectID = "KjO-BV-esE"; */ +"KjO-BV-esE.title" = "実行権を付与"; diff --git a/CotEditor/zh-Hans.lproj/SaveDocumentAccessory.strings b/CotEditor/zh-Hans.lproj/SaveDocumentAccessory.strings new file mode 100644 index 000000000..9a457f701 --- /dev/null +++ b/CotEditor/zh-Hans.lproj/SaveDocumentAccessory.strings @@ -0,0 +1,30 @@ +/* + + SaveDocumentAccessory.strings (Simplified Chinese) + + CotEditor + http://coteditor.com + + Created by 1024jp on 2016-03-06. + Localized by onevcat + + ------------------------------------------------------------------------------ + + © 2016 CotEditor Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +/* Class = "NSButtonCell"; title = "Give execute permission"; ObjectID = "KjO-BV-esE"; */ +"KjO-BV-esE.title" = "Give execute permission"; // FIXME: added