From dcfe16cb9b80db97251f28fb56d7e1c82af57343 Mon Sep 17 00:00:00 2001 From: relikd Date: Tue, 3 Feb 2026 19:19:54 +0100 Subject: [PATCH] ref: Exec, ActionFlag, Entry --- src/main.swift | 169 +++++++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 68 deletions(-) diff --git a/src/main.swift b/src/main.swift index 9ff3e52..f1ef486 100755 --- a/src/main.swift +++ b/src/main.swift @@ -52,7 +52,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { } func menuNeedsUpdate(_ menu: NSMenu) { - for entry in Entry.listDir(menu.title) { + for entry in listDir(menu.title) { let itm = menu.addItem(withTitle: entry.title, action: nil, keyEquivalent: "") itm.representedObject = entry itm.image = entry.icon() @@ -73,7 +73,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { } @objc private func menuItemCallback(sender: NSMenuItem) { - (sender.representedObject as! Entry).run() + let entry = sender.representedObject as! Entry + let cmd = Exec(file: entry.url, args: nil) + if entry.action == .Text { + cmd.editor() + } else { + cmd.run(verbose: entry.action == .Verbose) + } } // MARK: - Helper @@ -170,18 +176,100 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { } } -// MARK: - A menu item -struct Entry { - enum Flags { - case Verbose - case Text +// MARK: - Command executor + +struct Exec { + let file: URL + var args: [String]? = nil + + private func prepare() -> Process { + let proc = Process() + // proc.environment = ["HOME": "$HOME"] + proc.currentDirectoryURL = self.file.deletingLastPathComponent() + proc.executableURL = self.file + proc.arguments = args + return proc } + private func toPipe() -> Pipe { + let proc = prepare() + let io = Pipe() + proc.standardOutput = io + proc.standardError = io + proc.launch() + return io + } + + /// run command (ignoring output) + func run(verbose: Bool = false) { + let proc = prepare() + if verbose { + proc.executableURL = URL(fileURLWithPath: "/usr/bin/open") + proc.arguments = [self.file.path] + } + proc.launch() + } + + /// open result in default text editor + func editor() { + let p2 = Process() + p2.launchPath = "/usr/bin/open" + p2.arguments = ["-f"] + p2.standardInput = toPipe() + p2.launch() + } + + /// run command and return output + func read() -> String { + let data = toPipe().fileHandleForReading.readDataToEndOfFile() + return String(data: data, encoding: .utf8) ?? "" + } +} + + +// MARK: - static methods + +func listDir(_ path: String) -> [Entry] { + let target = URL(fileURLWithPath: path) + var rv: [Entry] = [] + for url in (try? FileManager.default.contentsOfDirectory(at: target, includingPropertiesForKeys: [.isDirectoryKey, .isExecutableKey])) ?? [] { + if url.hasDirectoryPath || FileManager.default.isExecutableFile(atPath: url.path) { + rv.append(Entry(url)) + } + } + return rv.sorted() +} + + +// MARK: - A menu item + +enum ActionFlag { + case Default + case Text + case Verbose + + static func from(_ filename: inout String) -> Self { + for (key, flag) in [ + "[txt]": ActionFlag.Text, + "[verbose]": .Verbose, + ] { + if filename.contains(key) { + filename = filename + .replacingOccurrences(of: key, with: "") + .replacingOccurrences(of: " ", with: " ") + return flag + } + } + return Default + } +} + +struct Entry { let order: Int - let title: String - let flags: [Flags] let url: URL + let title: String + let action: ActionFlag var isDir: Bool { url.hasDirectoryPath } @@ -189,43 +277,20 @@ struct Entry { self.url = url // TODO: remove file extension? var fname = url.lastPathComponent + var customOrder = 100 var idx = fname.firstIndex { !$0.isWholeNumber } ?? fname.startIndex // sort order if let order = Int(fname[.. [Entry] { - var rv: [Entry] = [] - for url - in (try? FileManager.default.contentsOfDirectory( - at: URL(fileURLWithPath: path), - includingPropertiesForKeys: [.isDirectoryKey, .isExecutableKey])) ?? [] - { - if url.hasDirectoryPath || FileManager.default.isExecutableFile(atPath: url.path) { - rv.append(Entry(url)) - } - } - return rv.sorted() - } - func icon() -> NSImage? { guard isDir else { return nil @@ -244,38 +309,6 @@ struct Entry { img?.size = NSMakeSize(16, 16) return img } - - func run() { - let proc = Process() - proc.currentDirectoryURL = self.url.deletingLastPathComponent() - // proc.environment = ["HOME": "$HOME"] - if self.flags.contains(.Verbose) { - proc.launchPath = "/usr/bin/open" - proc.arguments = [self.url.path] - } else { - proc.executableURL = self.url - } - - if self.flags.contains(.Text) { - // open result in default text editor - let io = Pipe() - proc.standardOutput = io - proc.standardError = io - - proc.launch() - - let p2 = Process() - p2.launchPath = "/usr/bin/open" - p2.arguments = ["-f"] - p2.standardInput = io - p2.launch() - - // let data = io.fileHandleForReading.readDataToEndOfFile() - // let output = String(data: data, encoding: .utf8) ?? "" - } else { - proc.launch() - } - } } extension Entry: Comparable {