Skip to content

Commit

Permalink
Disable editing actions when editor is not editable
Browse files Browse the repository at this point in the history
  • Loading branch information
1024jp committed Jan 18, 2025
1 parent 9d053dc commit 4e212ee
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ line_length:
warning: 1000

type_body_length:
warning: 1000
warning: 1200

function_body_length:
warning: 350
Expand Down
47 changes: 47 additions & 0 deletions CotEditor/Resources/Localizables/Models/Script.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,53 @@
}
}
},
"ScriptError.notEditable.description" : {
"extractionState" : "extracted_with_value",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Das Dokument kann nicht bearbeitet werden."
}
},
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "The document is not editable."
}
},
"en-GB" : {
"stringUnit" : {
"state" : "translated",
"value" : "The document is not editable."
}
},
"es" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "El documento no es editable."
}
},
"fr" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "Le document n’est pas modifiable."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "この書類は編集できません。"
}
},
"nl" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "Het document kan niet worden bewerkt."
}
}
}
},
"ScriptFileError.existence.description" : {
"extractionState" : "extracted_with_value",
"localizations" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ final class EditorTextViewController: NSViewController, NSServicesMenuRequestor,
// - Take Photo: .jpeg, .tiff
// - Scan Documents: .pdf, .tiff
// - Sketch: .png
if let returnType, NSImage.imageTypes.contains(returnType.rawValue) {
if let returnType, NSImage.imageTypes.contains(returnType.rawValue), self.textView.isEditable {
return (returnType != .png) ? self : nil
}

Expand Down Expand Up @@ -456,6 +456,8 @@ extension EditorTextViewController: NSUserInterfaceValidations {
func validateUserInterfaceItem(_ item: any NSValidatedUserInterfaceItem) -> Bool {

switch item.action {
case #selector(showUnicodeInputPanel):
return self.textView.isEditable
case #selector(toggleAdvancedCounter):
(item as? NSMenuItem)?.title = (self.advancedCounterView == nil)
? String(localized: "Advanced Character Count…", table: "AdvancedCharacterCount", comment: "menu item")
Expand Down
57 changes: 51 additions & 6 deletions CotEditor/Sources/Document Window/Text View/EditorTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// ---------------------------------------------------------------------------
//
// © 2004-2007 nakamuxu
// © 2014-2024 1024jp
// © 2014-2025 1024jp
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1131,6 +1131,46 @@ final class EditorTextView: NSTextView, CurrentLineHighlighting, MultiCursorEdit
override func validateUserInterfaceItem(_ item: any NSValidatedUserInterfaceItem) -> Bool {

switch item.action {
case #selector(pasteAsIs),
#selector(shiftRight),
#selector(shiftLeft),
#selector(shift),
#selector(convertIndentationToSpaces),
#selector(convertIndentationToTabs),
#selector(moveLineUp),
#selector(moveLineDown),
#selector(sortLinesAscending),
#selector(reverseLines),
#selector(shuffleLines),
#selector(deleteDuplicateLine),
#selector(duplicateLine),
#selector(deleteLine),
#selector(joinLines),
#selector(trimTrailingWhitespace),
#selector(patternSort),
#selector(insertSnippet),
#selector(surroundSelectionWithSingleQuotes),
#selector(surroundSelectionWithDoubleQuotes),
#selector(surroundSelectionWithParentheses),
#selector(surroundSelectionWithBraces),
#selector(surroundSelectionWithSquareBrackets),
#selector(surroundSelection),
#selector(snakecaseWord),
#selector(camelcaseWord),
#selector(pascalcaseWord),
#selector(encodeURL),
#selector(decodeURL),
#selector(exchangeFullwidth),
#selector(exchangeHalfwidth),
#selector(exchangeFullwidthRoman),
#selector(exchangeHalfwidthRoman),
#selector(exchangeKatakana),
#selector(exchangeHiragana),
#selector(normalizeUnicode(_:)),
#selector(inputBackSlash),
#selector(inputYenMark):
return self.isEditable

case #selector(selectColumnUp):
if let menuItem = item as? NSMenuItem {
switch self.layoutOrientation {
Expand All @@ -1149,6 +1189,7 @@ final class EditorTextView: NSTextView, CurrentLineHighlighting, MultiCursorEdit
assertionFailure()
}
}
return self.isEditable

case #selector(selectColumnDown):
if let menuItem = item as? NSMenuItem {
Expand All @@ -1168,6 +1209,7 @@ final class EditorTextView: NSTextView, CurrentLineHighlighting, MultiCursorEdit
assertionFailure()
}
}
return self.isEditable

case #selector(performTextFinderAction):
guard let action = TextFinder.Action(rawValue: item.tag) else { return false }
Expand All @@ -1179,22 +1221,25 @@ final class EditorTextView: NSTextView, CurrentLineHighlighting, MultiCursorEdit
case #selector(straightenQuotesInSelection):
// -> Although `straightenQuotesInSelection(:_)` actually works also when selections are empty,
// disable it to make the state same as `replaceQuotesInSelection(_:)`.
return !self.selectedRange.isEmpty
return self.isEditable && !self.selectedRange.isEmpty

case #selector(toggleComment):
(item as? NSMenuItem)?.title = self.canUncomment(partly: false)
? String(localized: "Uncomment", table: "MainMenu")
: String(localized: "Comment Out", table: "MainMenu")
return (self.commentDelimiters.inline != nil) || (self.commentDelimiters.block != nil)
return self.isEditable && ((self.commentDelimiters.inline != nil) || (self.commentDelimiters.block != nil))

case #selector(commentOut):
return self.isEditable

case #selector(inlineCommentOut):
return (self.commentDelimiters.inline != nil)
return self.isEditable && (self.commentDelimiters.inline != nil)

case #selector(blockCommentOut):
return (self.commentDelimiters.block != nil)
return self.isEditable && (self.commentDelimiters.block != nil)

case #selector(uncomment(_:)):
return self.canUncomment(partly: true)
return self.isEditable && self.canUncomment(partly: true)

default: break
}
Expand Down
5 changes: 5 additions & 0 deletions CotEditor/Sources/Models/Scripts/Script.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ enum ScriptError: LocalizedError {
case standardError(String)
case noInputTarget
case noOutputTarget
case notEditable


var errorDescription: String? {
Expand All @@ -153,6 +154,10 @@ enum ScriptError: LocalizedError {
String(localized: "ScriptError.noOutputTarget.description",
defaultValue: "No document to put output.",
table: "Script")
case .notEditable:
String(localized: "ScriptError.notEditable.description",
defaultValue: "The document is not editable.",
table: "Script")
}
}
}
4 changes: 4 additions & 0 deletions CotEditor/Sources/Models/Scripts/UnixScript.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,22 @@ struct UnixScript: Script {
switch type {
case .replaceSelection:
guard let editor else { throw ScriptError.noOutputTarget }
guard editor.isEditable else { throw ScriptError.notEditable }
editor.insert(string: output, at: .replaceSelection)

case .replaceAllText:
guard let editor else { throw ScriptError.noOutputTarget }
guard editor.isEditable else { throw ScriptError.notEditable }
editor.insert(string: output, at: .replaceAll)

case .insertAfterSelection:
guard let editor else { throw ScriptError.noOutputTarget }
guard editor.isEditable else { throw ScriptError.notEditable }
editor.insert(string: output, at: .afterSelection)

case .appendToAllText:
guard let editor else { throw ScriptError.noOutputTarget }
guard editor.isEditable else { throw ScriptError.notEditable }
editor.insert(string: output, at: .afterAll)

case .newDocument:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// ---------------------------------------------------------------------------
//
// © 2004-2007 nakamuxu
// © 2014-2024 1024jp
// © 2014-2025 1024jp
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -299,7 +299,8 @@ extension Document {
let arguments = command.evaluatedArguments,
let searchString = arguments["targetString"] as? String, !searchString.isEmpty,
let replacementString = arguments["newString"] as? String,
let textView = self.textView
let textView = self.textView,
textView.isEditable
else { return 0 }

let options = NSString.CompareOptions(scriptingArguments: arguments)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// ---------------------------------------------------------------------------
//
// © 2004-2007 nakamuxu
// © 2014-2024 1024jp
// © 2014-2025 1024jp
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -38,7 +38,7 @@ enum InsertionLocation {
extension NSTextView {

/// Inserts string at desired location and select inserted range.
final func insert(string: String, at location: InsertionLocation) {
@discardableResult final func insert(string: String, at location: InsertionLocation) -> Bool {

let replacementRange: NSRange = switch location {
case .replaceSelection:
Expand All @@ -53,7 +53,7 @@ extension NSTextView {

let selectedRange = NSRange(location: replacementRange.location, length: (string as NSString).length)

self.replace(with: string, range: replacementRange, selectedRange: selectedRange,
actionName: String(localized: "Insert Text", table: "MainMenu"))
return self.replace(with: string, range: replacementRange, selectedRange: selectedRange,
actionName: String(localized: "Insert Text", table: "MainMenu"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
// ---------------------------------------------------------------------------
//
// © 2017-2024 1024jp
// © 2017-2025 1024jp
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -29,7 +29,7 @@ import SwiftUI
import Defaults
import TextFind

final class MultipleReplaceViewController: NSViewController {
final class MultipleReplaceViewController: NSViewController, NSUserInterfaceValidations {

// MARK: Public Properties

Expand Down Expand Up @@ -86,6 +86,19 @@ final class MultipleReplaceViewController: NSViewController {

// MARK: Actions

func validateUserInterfaceItem(_ item: any NSValidatedUserInterfaceItem) -> Bool {

switch item.action {
case #selector(batchReplaceAll):
return self.client?.isEditable == true
case nil:
return false
default:
return true
}
}


/// The segmented control for the add/remove actions was clicked.
@IBAction func addRemove(_ sender: NSSegmentedControl) {

Expand Down

0 comments on commit 4e212ee

Please sign in to comment.