AppleScript: Wie öffne ich eine Textdatei und bewege den Cursor an eine bestimmte Stelle (angezeigt durch ein bestimmtes Zeichen)?

Ich habe eine .txt-Datei auf meinem Computer gespeichert. Ich möchte, dass meine Automator-Anwendung die .txt-Datei öffnet und dann die Position des Cursors auf die erste leere Zeile in der Datei verschiebt.

Zum Beispiel habe ich eine .txt-Datei mit dem Titel My Fruit Log.txt auf meinem Computer gespeichert. So könnte der Inhalt der .txt-Datei aussehen:

Im obigen Fall möchte ich also, dass die Datei geöffnet wird und der Cursor dann in die zweite Zeile der Datei verschoben wird.

Hinweis: Es ist nicht unbedingt die zweite Zeile von oben, an die der Cursor gesendet werden soll. Je nachdem, welcher Text bereits in die Datei geschrieben wurde, möchte ich den Cursor möglicherweise in einer unteren Zeile haben. Zum Beispiel:

Im obigen Fall möchte ich, dass der Cursor in die sechste Zeile bewegt wird.

Die Position, an der ich den Cursor haben möchte, ist immer mindestens die zweite Zeile von oben, aber es könnte so weit unten sein wie die siebte Zeile von oben.

Der zuverlässigste Weg, um anzugeben, wo der Cursor platziert werden soll, ist also "auf der ersten Instanz einer leeren Zeile in der Datei".

Ich habe bereits den Code zum Öffnen der Datei in TextEdit (aus der obersten Antwort dieser Stack Overflow-Frage entlehnt ):

set Target_Filepath to POSIX file "/Users/Me/Desktop/My Fruit Log.txt"

tell application "Finder" to open Target_Filepath

Jetzt brauche ich den Code, um den Cursor zu bewegen. Die Standardposition des Cursors ist die erste Zeile der Datei.

Ich denke, es kann nicht mit TextEdit gemacht werden, weil es eine Suchfunktion in der AppleScript-Bibliothek vermisst. BBEdit und TextWrangler sollten jedoch funktionieren, da sie beide einen bieten.

Antworten (3)

Ich weiß nicht, ob es einen einfachen oder hübschen Weg gibt, das zu tun, was Sie fragen. Mit anderen Worten, Sie können nicht einfach etwas wie sagen open target file and move cursor to first empty line, aber der folgende Code wird dies tun.

set filePathName to POSIX path of (path to desktop as string) & "My Fruit Log.txt"
set firstEmptyLineNumber to (do shell script "awk '$1 == \"\" {print NR;exit;}' \"" & filePathName & "\"")
do shell script "open -e " & quoted form of filePathName
tell application "TextEdit" to activate
tell application "System Events" to tell process "TextEdit"
    repeat (firstEmptyLineNumber - 1) times
        key code 125 # Down Arrow
    end repeat
end tell

Der obige Code ist so codiert, dass er die Textdatei in TextEdit öffnet, was open -eim zweiten
do shell script Befehl geschieht, und er ist so codiert, weil System Events wissen muss, wohin die Tastenanschläge mit dem Pfeil nach unten gesendet werden sollen . Wenn Sie einen anderen Texteditor wünschen, entfernen Sie
den -eund der open Befehl öffnet ihn in jeder App, mit der die .txt- Dateierweiterung zum Öffnen registriert ist. Dann müssen Sie auch ändern:

tell application "System Events" to tell process "TextEdit"

Zu:

tell application "System Events" to tell front process

Und ersetzen:

tell application "TextEdit" to activate

Mit:delay 1

Im ersten do shell script Befehl wird die Zeilennummerawk der ersten leeren Zeile abgerufen und beendet, und dies wird verwendet, um zu berechnen, wie viele Pfeiltasten nach unten gedrückt werden müssen .repeat


delay Ich habe meine ursprüngliche Antwort leicht geändert, um den Befehl loszuwerden, wollte aber meine Einstellung zur Antwort von adc hinzufügen und dabei alle menu_clickDinge eliminieren.

set filePathName to POSIX path of (path to desktop as string) & "My Fruit Log.txt"
set firstEmptyLineNumber to (do shell script "awk '$1 == \"\" {print NR;exit;}' \"" & filePathName & "\"")
if firstEmptyLineNumber = "" then set firstEmptyLineNumber to 1 as string
do shell script "open -e " & quoted form of filePathName
tell application "TextEdit" to activate
tell application "System Events" to tell process "TextEdit"
    key code 37 using command down # ⌘L
    keystroke firstEmptyLineNumber
    keystroke return
    key code 123 # Left Arrow - So the line is not highlighted.
end tell

Aktualisieren:

Der folgende Code wurde gegenüber dem obigen Code oben in meiner Antwort geändert, nicht in meiner Antwort auf arc, obwohl er auch dort anwendbar ist, um das Problem zu beheben, das Sie haben, wenn TextEdit zwei Wagenrückläufe anstelle der erwarteten und normalen zwei schreibt Zeilenvorschübe für eine Leerzeile nach einer Inhaltszeile oder zwei Leerzeilen hintereinander.

set filePathName to POSIX path of (path to desktop as string) & "My Fruit Log.txt"
set firstEmptyLineNumber to (do shell script "awk '$1 == \"\" {print NR;exit;}' \"" & filePathName & "\"")
if firstEmptyLineNumber is equal to "" then  
    set firstEmptyLineNumber to (do shell script "awk '/\r\r/{print NR+1;exit;}' \"" & filePathName & "\"")
end if
do shell script "open -e " & quoted form of filePathName
tell application "TextEdit" to activate
tell application "System Events" to tell process "TextEdit"
    repeat (firstEmptyLineNumber - 1) times
        key code 125 # Down Arrow
    end repeat
end tell

Hinweis: Obwohl der geänderte Code mit Ihrer testfile.txt- Datei über den Link in Ihrem Kommentar funktioniert, unterschreibe ich persönlich diese Problemumgehung nicht und würde stattdessen die Hauptursache des Problems herausfinden und es und Ihre Dateien beheben!

Clevere Lösung. Aber aus irgendeinem Grund funktioniert Ihr Code bei mir nicht. Es öffnet die .txt-Datei in TextEdit, aber der Cursor bewegt sich nicht. Ich habe versucht, zu wechseln delay 1, um delay 10sicher zu sein; Trotzdem bewegte es den Cursor nicht. Dann habe ich display dialog firstEmptyLineNumbernach der zweiten Zeile deinen Code eingefügt. Als ich den Code ausführte, erschien ein völlig leeres Dialogfeld. Dies ist die TXT-Datei , die ich zum Testen Ihres Codes verwende. Wenn Sie diese TXT-Datei verwenden, funktioniert der Code ordnungsgemäß auf Ihrem Computer?
Die Datei „testfile.txt“ wurde auf meinem Mac erstellt. So wurde es erstellt (und ich kenne keine andere Möglichkeit, eine .txt-Datei auf einem Mac zu erstellen): Ich habe ein neues Dokument in TextEdit erstellt, den Text eingegeben, auf das Menü Format geklickt und dann auf Einfacher Text geklickt und gespeichert die Datei als „testfile.txt“ mit der Standardcodierungsoption „Unicode (UTF-8)“. Ich sehe, was Sie im Hex-Editor sehen; 0D0DZwischen der vierten und fünften Zeile der Datei befindet sich ein . 0D0DIst es möglich, Ihren Code so zu bearbeiten, dass er sowohl als auch 0A0Dals neue Leerzeilen erkennt ?
@rubik's sphere, Bitte löschen Sie alle bis auf Ihren ersten Kommentar unter meiner Antwort bis zu diesem Punkt, da sie jetzt nicht wirklich benötigt werden, da wir wissen, dass das Problem darin besteht, dass TextEdit auf Ihrem System schreibt, anstatt wie es auf einem Mac üblich 0Dist 0A. Ich habe versucht, Ihr Problem in TextEdit unter OS X 10.11.6 und macOS 10.12 zu reproduzieren, indem ich das tat, was Sie sagen, und kann es nicht reproduzieren. Alle meine Zeilenenden sind 0Aso, wie sie sein sollten, und daher zeigt die leere Zeile wie 0A0Aim Hex-Editor zwei Zeilenvorschübe hintereinander, wie es standardmäßig auf einem Mac vorgesehen ist, nicht zwei Wagenrückläufe.
@rubik's sphere, ich habe meine Antwort aktualisiert, um Ihr Problem zu lösen, und sie in Ihrer testfile.txt- Datei über den Link in Ihrem Kommentar getestet, und sie funktioniert. FWIW
Wow, der neue Code funktioniert wirklich. Vielen Dank user3439894. Ich werde Ihren Rat zur Diagnose des Grundproblems weiterhin befolgen, aber das wird mich in der Zwischenzeit aufhalten. Was hat Sie dazu bewogen, den delayBefehl vollständig aus Ihrem Code zu entfernen? Ich dachte, Sie hätten ursprünglich den delayBefehl eingefügt, um sicherzustellen, dass das Drücken des Pfeils nach unten nicht vorzeitig erfolgt. (Nicht, dass ich damit ein Problem hätte; ich bin nur neugierig.)
@rubiks Sphäre, ich habe den delay Befehl entfernt , weil ich den tell application "TextEdit" to activate Befehl an seiner Stelle hinzugefügt habe und er eine kleine Verzögerung verursacht und auch den Fokus auf die App zwingt. Ja, der open -e Befehl legt den Fokus auch auf TextEdit, aber in meinen Tests schien dies besser zu funktionieren. Ohne sie delaywar die Verwendung notwendig.

Hier ist ein AppleScript für TextWrangler, um zum Ende des ersten Absatzes einer Textdatei zu springen:

try
    tell application "TextWrangler"
        find "(?=\\r^\\r|\\A)" searching in text of front text window options {search mode:grep, wrap around:false, backwards:false, case sensitive:false} with selecting match
    end tell
end try

Durch Hinzufügen eines zweiten Ausdrucks direkt nach, (?=\\r^\\r|\\A)aber innerhalb der Anführungszeichen sollte man in der Lage sein, zur nächsten Zeile zu springen. Da ich nicht weiß, was das (?=\\r^\\r|\\A)wirklich bedeutet, kann ich dir nicht weiter helfen.

Das Problem, das ich sehe, ist, dass TextWrangle sich an die Cursorposition im Dokument erinnert, als es zuletzt in TextWrangler gespeichert wurde, und der Cursor möglicherweise nicht am Anfang der Datei steht, wie es bei TextEdit der Fall ist, wenn es geöffnet wird. So wie es codiert ist, kann es auf mehr als eine Weise fehlschlagen, auf meinem System. Mit anderen Worten, wenn ich die Datei am Ende des ersten Absatzes gespeichert habe, geht sie zum Ende des zweiten Absatzes, wenn ich den Code ausführe . Oder wenn ich am Ende des zweiten Absatzes speichere, wird beim Ausführen des Codes darauf hingewiesen , da zu diesem Zeitpunkt nur drei Absätze in der Datei vorhanden sind.

Ich würde dies wahrscheinlich mit etwas wie Ruby und TextMate angehen – ein Ruby-Skript könnte bestimmen, welche Zeile ausgewählt werden soll (wahrscheinlich durch einen einfachen regulären Ausdruck) und gegebenenfalls sogar das Datum für den nächsten Tag hinzufügen. TextMate kann auf der Befehlszeile aufgerufen werden, um den Cursor beispielsweise auf eine bestimmte Zeile zu bewegen mate -l 7.

Wenn Sie jedoch nur AppleScript in TextEdit und awkaus der Antwort von user3439894 verwenden, verwendet eine etwas robustere Methode zum Navigieren zu einer bestimmten Zeile Systemereignisse und das Menüelement "Zeile auswählen" (Befehl + L) von TextEdit.

Ich habe auch eine Funktion von MacOSXHints verwendet, da das Erstellen von Menüskripten in AppleScript sehr mühsam ist. Die Beseitigung der menu_click-Funktion ist eine Übung für den Leser.

set filePathName to POSIX path of (path to desktop as string) & "My Fruit Log.txt"
set firstEmptyLineNumber to (do shell script "awk '$1 == \"\" {print NR;exit;}' \"" & filePathName & "\"")
if firstEmptyLineNumber = "" then set firstEmptyLineNumber to 1

do shell script "open -e " & quoted form of filePathName

menu_click({"TextEdit", "Edit", "Find", "Select Line..."})


tell application "System Events"
    keystroke firstEmptyLineNumber
    keystroke return
end tell




-- `menu_click`, by Jacob Rus, September 2006
-- 
-- Accepts a list of form: `{"Finder", "View", "Arrange By", "Date"}`
-- Execute the specified menu item.  In this case, assuming the Finder 
-- is the active application, arranging the frontmost folder by date.

on menu_click(mList)
    local appName, topMenu, r

    -- Validate our input
    if mList's length < 3 then error "Menu list is not long enough"

    -- Set these variables for clarity and brevity later on
    set {appName, topMenu} to (items 1 through 2 of mList)
    set r to (items 3 through (mList's length) of mList)

    -- This overly-long line calls the menu_recurse function with
    -- two arguments: r, and a reference to the top-level menu
    tell application "System Events" to my menu_click_recurse(r, ((process appName)'s ¬
        (menu bar 1)'s (menu bar item topMenu)'s (menu topMenu)))
end menu_click

on menu_click_recurse(mList, parentObject)
    local f, r

    -- `f` = first item, `r` = rest of items
    set f to item 1 of mList
    if mList's length > 1 then set r to (items 2 through (mList's length) of mList)

    -- either actually click the menu item, or recurse again
    tell application "System Events"
        if mList's length is 1 then
            click parentObject's menu item f
        else
            my menu_click_recurse(r, (parentObject's (menu item f)'s (menu f)))
        end if
    end tell
end menu_click_recurse
menu_clickSie könnten all dieses Zeug (was übrigens interessant ist) durch zwei Codezeilen ersetzen . Platzieren Sie tell application "TextEdit" to activatedirekt vor dem tell application "System Events"Block und fügen Sie key code 37 using command down(das ist ⌘L, die Tastenkombination für "Linie auswählen ...") oder keystroke "l" using command down darüber keystroke firstEmptyLineNumberin den tell application "System Events"Block ein. Ich würde auch key code 123(Pfeil nach rechts) danach hinzufügen keystroke return, damit die Zeile nicht hervorgehoben wird.