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