AppleScript: ¿Cómo abrir un archivo de texto y mover el cursor a una ubicación específica (señalada por un carácter específico)?

4

Tengo un archivo .txt guardado en mi computadora. Quiero que mi aplicación Automator abra el archivo .txt y luego mueva la ubicación del cursor a la primera línea en blanco del archivo.

Por ejemplo, tengo un archivo .txt titulado My Fruit Log.txt guardado en mi computadora. Este es el aspecto que puede tener el contenido del archivo .txt:

Entonces, en la instancia anterior, quiero que se abra el archivo y luego el cursor se mueva a la segunda línea del archivo.

Nota: No es necesariamente la segunda línea desde la parte superior donde quiero que se envíe el cursor. Dependiendo de qué texto ya se haya escrito en el archivo, es posible que desee colocar el cursor en una línea inferior. Por ejemplo:

En el caso anterior, me gustaría que el cursor se mueva a la sexta línea.

La ubicación donde deseo el cursor siempre será al menos la segunda línea desde la parte superior, pero podría estar tan abajo como la séptima línea desde la parte superior.

Por lo tanto, la forma más confiable de articular dónde quiero que se coloque el cursor es "en la primera instancia de una línea en blanco en el archivo".

Ya tengo el código para abrir el archivo en TextEdit (tomado de la respuesta principal de esta pregunta de desbordamiento de pila ):

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

tell application "Finder" to open Target_Filepath

Ahora necesito el código para mover el cursor. La ubicación predeterminada del cursor es la primera línea del archivo.

    
pregunta rubik's sphere 24.11.2016 - 02:00

3 respuestas

4

No sé si hay una manera fácil o bonita de hacer lo que me estás pidiendo. En otras palabras, no puedes simplemente decir algo como open target file and move cursor to first empty line , sin embargo, el código a continuación lo hará.

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

El código anterior está codificado para abrir el archivo de texto en TextEdit, que es lo que open -e en el segundo comando de do shell script está haciendo y está codificado de esta manera porque los eventos del sistema necesitan saber a dónde enviar las pulsaciones flecha abajo . Si desea un editor de texto diferente, elimine
-e y el comando open lo abrirá en cualquier aplicación en la que esté registrada la extensión de archivo .txt abrir con. Entonces también necesitarás cambiar:

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

Para:

tell application "System Events" to tell front process

Y reemplazar:

tell application "TextEdit" to activate

Con: delay 1

En el primer comando do shell script , awk obtiene el número de línea de la primera línea vacía y sale y esto es lo que se usa para calcular cuántos < em> flecha abajo pulsaciones de tecla a repeat .

Modifiqué ligeramente mi respuesta original para deshacerme del comando delay , pero quería agregar mi opinión sobre la respuesta de adc a la vez que eliminaba todas las cosas de menu_click .

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

Actualizar:

El código a continuación se modificó desde el código que aparece arriba en la parte superior de mi respuesta, no mi respuesta a la respuesta del arco, aunque también es aplicable allí, para abordar el problema está haciendo que TextEdit escriba dos retornos de carro en lugar de las dos líneas de línea esperadas y normales para una línea vacía después de una línea que contiene contenido o dos líneas vacías en una fila.

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

Nota: Aunque el código modificado funciona con su archivo testfile.txt desde el enlace de su comentario, no obstante, personalmente no me suscribo a esta solución alternativa, y en lugar de eso, descubriría la causa raíz del problema y lo solucionaría junto con sus archivos.     

respondido por el user3439894 24.11.2016 - 03:27
0

Aquí hay un AppleScript para TextWrangler para saltar al final del primer párrafo de un archivo de texto:

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

Añadiendo una segunda expresión directamente después de (?=\r^\r|\A) , pero dentro de las comillas, uno debería poder saltar a la siguiente línea. Como no sé qué significa (?=\r^\r|\A) realmente, no puedo ayudarte más.

    
respondido por el klanomath 24.11.2016 - 03:20
0

Probablemente me acercaría a esto usando algo como Ruby y TextMate: una secuencia de comandos de Ruby podría determinar qué línea elegir (probablemente por una expresión regular simple) e incluso agregar la fecha para el día siguiente, si corresponde. Se puede invocar TextMate en la línea de comandos para mover el cursor a una línea específica, por ejemplo, por mate -l 7 .

Dicho esto, usar solo AppleScript en TextEdit y awk de user3439894 responde a una forma algo más robusta de navegar a una línea específica usando los eventos del sistema y el elemento de menú "Seleccionar línea" (Comando + L) de TextEdit.

También usé una función de MacOSXHints porque las secuencias de comandos del menú en AppleScript son un gran dolor. La eliminación de la función menu_click es un ejercicio para el lector.

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
    
respondido por el adc 24.11.2016 - 05:27

Lea otras preguntas en las etiquetas