I want to use hammerspoon to find one specific chrome tab across al chrome windows across all spaces.
The only way I was able to achieve this was using osascript, which I don't like much because it means to use a big multi-line string inside Lua. I will prefer to use native hammerspoon methods with Lua.
Just in case, here is my version using osascript that works perfectly:
local function osa()
local tabName = "whatsapp"
local script = [[
tell application "Google Chrome" to activate
tell application "Google Chrome"
set found to false
repeat with theWindow in windows
repeat with theTab in (tabs of theWindow)
if the title of theTab contains "%s" then
set found to true
set index of theWindow to 1
return id of theTab
end if
end repeat
end repeat
return found
end tell
]]
local success, windowID, errors = hs.osascript.applescript(string.format(script, tabName))
print(success, windowID, type(windowID), hs.inspect(errors))
if success == false then
hs.alert.show("Tab with name '" .. tabName .. "' not found.")
else
hs.alert.show("Tab '" .. tabName .. "' found and brought to front.")
end
end
Related
I'm working on a homework reminder app. I recently asked a question concerning using "write" properly and had my question answered. My script was working perfectly, but now it has stopped writing anything to my file. I must have changed something, but I can't figure out what's wrong. Any suggestions?
(Please Note: This is still a work-in-progress and not everything is competed; however the part using "write" should not be effected)
Code:
set saveFile to (path to desktop as text) & "Script Log.txt"
set assignments to read file the saveFile from 1 to eof using delimiter "*"
repeat
display dialog "What would you like to do?" buttons {"New Assignment", "Delete/Edit Assignment", "Exit"}
set function to button returned of result
if function = "New Assignment" then
display dialog "What subject is this assignment for?" default answer ""
set subject to text returned of result
display dialog "What do you need to bring home for this assignment?" default answer ""
set materials to text returned of result
display dialog "What is the assignment?" default answer ""
set instructions to text returned of result
(choose from list {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Long-Term"} with prompt "When is this assignment due?")
set dueDate to result as text
if dueDate = "Long-Term" then
display dialog "When is this due?" default answer ""
set dueDat to text returned of result
end if
set assignments to {assignments & (subject & ": You need to bring " & materials & " home. It is due on " & dueDate & ". For this assignment, you need to " & instructions & ".")}
else if function = "Delete/Edit Assignment" then
(choose from list {item 1 of assignments} with prompt "Which assignmnet would you like to delete/edit?")
else if function = "Exit" then
set fullText to ""
repeat with i from 1 to number of items in assignments
set thisItem to item i of assignments & "*"
set fullText to fullText & thisItem
if i is not number of items in assignments then set fullText to fullText & return
end repeat
my scriptLog(fullText)
exit repeat
end if
end repeat
on scriptLog(thisText)
try
open for access file the saveFile with write permission
write (thisText & return) to file the saveFile starting at eof
close access file the saveFile
on error
try
close access file the saveFile
end try
end try
end scriptLog
display dialog assignments
The saveFile is not defined inside the scriptLog handler.
Change the top line : set saveFile to (path to desktop as text) & "Script Log.txt"
to a property, since it value is static. A property is automaticly global to the rest of the code and it's handlers.
property saveFile : (path to desktop as text) & "Script Log.txt"
The other thing to remember is that try blocks can hide any errors when you are debugging so you should remember to comment them out if you are debugging.
I am trying to write an applescript which will run via a launch agent. What the script needs to do is edit a user preference plist file so that default save locations are specific to that user. I am aware that this can be done by just setting "~/documents" as the location in the template plist. But Premier Pro for example also needs to write scratch files to a local drive. For simplicity I would like each user to have these put in a locations based on their username. This script will only need to run if the local profile has just been created from a template at first log on.
I have started by using some sample code found on this site and just making a simple test below. This test should edit a txt file and replace one word with another. This script is currently not working. When tested it opens up test.txt in TextEdit but does nothing more. No errors are displayed either.
Thank you in advance
John.
replaceText("replace this", "replace with this", "/Volumes/USB_Drive/test.txt")
on replaceText(search_string, replacement_text, this_document)
tell application "TextEdit"
open this_document
set AppleScript's text item delimiters to the search_string
set this_text to the text of the front document as list
set AppleScript's text item delimiters to the replacement_text
set the text of the front document to (this_text as string)
close this_document saving yes
end tell
end replaceText
Here an version that doesn't need text edit. It will read the file in utf-8 encoding, update it's contents and store that back into the file as utf-8 encoded text. The reason I use an try block around writing the file is that there will be an error if another application has the file open with read permission at the same time. The considering case block can be wrapped around the set ti to every text item of theContent if you want the search and replace case sensitive. There is no need for this to be active when you replace the string, only for finding it.
set stringToFind to "replace that"
set stringToReplace to "with this"
set theFile to choose file
set theContent to read theFile as «class utf8»
set {oldTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, stringToFind}
set ti to every text item of theContent
set AppleScript's text item delimiters to stringToReplace
set newContent to ti as string
set AppleScript's text item delimiters to oldTID
try
set fd to open for access theFile with write permission
set eof of fd to 0
write newContent to fd as «class utf8»
close access fd
on error
close access theFile
end try
Well, yes, as #dj_bazzie_wazzie points out, you really don't need a text editor for this, you can use the terminal and do something like:
perl -pi -e 's/old text/new text/g' /path/to/theFile.plist
which of course you can use in AppleScript with the powerful do shell script command:
do shell script "perl -pi -e 's/" & search_string & "/" & replacement_text & "/g' " & quoted form of (POSIX path of file_path)
--assuming file_path is a variable with Mac-style (colon-separated) file path.
Modified from http://discussions.apple.com/message/20542594#20542594, the handler below does what you want. I made a few changes and added your variables. A few notes: (1) the 'my' before the handler call makes sure it is seen as the script's handler and not something TextEdit should interpret 'internally' (because it is in a tell block); (2) 'considering case' makes the handler case sensitive, which I assume you want; (3) You might consider something like TextWrangler, which has robust and feature-rich AppleScript support, and includes text replacement in its AS dictionary, as does Smile, a fantastic Script Editor (which can work with text, and formats plist files nicely).
tell application "TextEdit"
set workingWin to open this_document
set this_text to the text of the workingWin
set the text of the workingWin to (my replaceText(this_text, search_string, replacement_text))
close workingWin saving yes
end tell
to replaceText(someText, oldItem, newItem)
(*
replace all occurances of oldItem with newItem
parameters - someText [text]: the text containing the item(s) to change
oldItem [text, list of text]: the item to be replaced
newItem [text]: the item to replace with
returns [text]: the text with the item(s) replaced
*)
considering case
set {tempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, oldItem}
try
set {itemList, AppleScript's text item delimiters} to {text items of someText, newItem}
set {someText, AppleScript's text item delimiters} to {itemList as text, tempTID}
on error errorMessage number errorNumber -- oops
set AppleScript's text item delimiters to tempTID
error errorMessage number errorNumber -- pass it on
end try
end considering
return someText
end replaceText
I have found this code which allows me to drag and drop files onto to script icon and put them in a specified directory:
Const MyDestinationFolder = "C:\Temp\"
Const OverwriteExisting = True
Dim objFile,objFolder
Dim Arg
Set objFSO = CreateObject("Scripting.FileSystemObject")
If WScript.Arguments.Count > 0 Then
For Each Arg in Wscript.Arguments
Arg = Trim(Arg)
If InStr(Arg,".") Then
' Assume a File
Set objFile = objFSO.GetFile(Arg)
' Copy file to the Dest Folder using the same name
objFile.Copy MyDestinationFolder & objFile.Name,OverwriteExisting
Else
'Assume a Folder
Set objFolder = objFSO.GetFolder(Arg)
' Copy Folder to the Dest Folder
objFolder.Copy MyDestinationFolder, OverwriteExisting
End If
Next
End If
However I would like to make a script that runs and has a simple rectangle that says, drag and drop here. If this is at all possible, that would be great. Thanks!
You can add a GUI to VBScript programs by using "HTML Applications (HTAs)". Start your research here:
Introduction to HTML Applications (HTAs)
Extreme Makeover: Wrap Your Scripts Up in a GUI Interface
A Scriptomatic You Can Call Your Own
HTML Application
HTML Applications (HTAs)
Scripting Eye for the GUI Guy
and - of course
stackoverflow questions tagged hta
After second thoughts on "Drag & Drop", I found:
this claim and that .HTA (not tested)
I'm trying to make a droplet applscript app. It should do:
when a folder is dropped it should "scan" the folder,its subfolders and files
every file with a specific extension (such as: .txt" should be opened in an program and something should be done
that's all
I get this error when I detected the right file and if it is trying to open it (the app won't be started- before that I get this error and the script cancels):class nmxt of alias "the path to the file" could not be read
Currently my script:
on open {input}
set theFiles to (getFilesRecursively(input, "plhs"))
repeat with oneFile in theFiles
if name extension of oneFile is "plhs" then
tell application "Applic"
open oneFile
activate
tell application "System Events"
tell process "Applic"
click menu item "Save" of menu 1 of menu bar item "File" of menu bar 1
end tell
end tell
end tell
end if
end repeat
end open
on getFilesRecursively(fContainer, fExt)
tell application "Finder"
set recursiveFileList to entire contents of fContainer as alias list
set resultFileList to {}
repeat with aFile in recursiveFileList
if name extension of aFile contains fExt then
set resultFileList to resultFileList & aFile
end if
end repeat
end tell
return resultFileList
end getFilesRecursively
Here is a germinal script that should get you going:
property kTargetFileExtension : "txt"
property pValidFileList : {}
on open of theFiles -- Executed when files or folders are dropped on the script
set fileCount to (get count of items in theFiles)
repeat with thisFile from 1 to fileCount
set theFile to item thisFile of theFiles
tell application "System Events"
set file_info to get info for theFile
end tell
if visible of file_info is true then -- check for the file extension here as well
if folder of file_info is true then
my createList(theFile)
else
set fileName to name of file_info
set targetFileFound to isTargetFile(fileName, kTargetFileExtension) of me
if (targetFileFound) then
set end of pValidFileList to theFile
end if
end if
end if
end repeat
display dialog "pValidFileList = " & pValidFileList
(* do something with your files listed in pValidFileList here *)
end open
on createList(mSource_folder)
set item_list to ""
tell application "System Events"
set item_list to get the name of every disk item of (mSource_folder as alias)
end tell
set item_count to (get count of items in item_list)
repeat with i from 1 to item_count
set the_properties to ""
set the_item to item i of the item_list
set fileName to the_item
set the_item to ((mSource_folder & the_item) as string) as alias
tell application "System Events"
set file_info to get info for the_item
end tell
if visible of file_info is true then -- check for the file extension here as well
if folder of file_info is true then
my createList(the_item)
else
set targetFileFound to isTargetFile(fileName, kTargetFileExtension) of me
if (targetFileFound) then
set end of pValidFileList to the_item
end if
end if
end if
end repeat
end createList
on isTargetFile(theFilename, theTargetExtension) -- (string, string) as boolean
set AppleScript's text item delimiters to "."
set fileNameList to every text item of theFilename
set AppleScript's text item delimiters to ""
try
set theFileExtension to item 2 of fileNameList as string
on error
return false
end try
if theFileExtension is theTargetExtension then
return true
end if
return false
end isTargetFile
A couple things to note:
System Events is the current best practice for getting lists and information about files. Just asking for the entire contents is faster but known to be unreliable. This method of crawling manually is slower but there is no doubt you will be getting the files you need.
isTargetFile actually just works with the filename as a string, as opposed to relying on the system to give the information. Six of one, half dozen of the other if you ask me, but this does reduce the number of calls to the system, so I imagine it makes this a bit faster.
I also tend to add an on run {} block to these things to allow for manual selection of a folder. Doing so also facilitates testing.
How to use:
Save the script as an application, and you should get a droplet (the Applescript application icon with the arrow pointing down).
on open of theFiles is the equivalent of main(). You can drop any combination of files and folders onto the droplet, and it will handle the rest. It ends up with a list of target files that you can then loop through for processing. I will leave it as an exercise for you to add in that bit.
To customize the target, change the string in the first line, property kTargetFileExtension : "txt", to whatever extension you are looking for. This can also be changed to an array—property kTargetFileExtension : {"txt", "rtf", "doc} for example—but you will also need to update isTargetFile(theFilename, theTargetExtension) to loop through those as well.
Beyond that, this just works. Right now, it will gather a list of txt files for processing.
Add salt to taste.
I need to version control a Microsoft Access 2007 database and application. Currently everything is contained in a single mdb file.
The application includes:
Forms
VBA code
Actual database
I would assume I need to separate the database from the forms/code. I would like to be able to version control the forms/code as text to support version diffs.
At the moment I don't have access to SourceSafe (I heard there may be some access support) so I would prefer a solution that would work with subversion or git.
Access 2007 has a feature where you can split a DB into its Tables/Queries (backend) and Forms/Reports (front-end). Since your question mentions only version controlling the forms and modules, this might be a more elegant solution. I don't know where modules go after the split, so that might be a stumbling block.
Microsoft offers VSTO (Visual Studio Tools for Office), which will let you develop in VS and run version control via any VS plugin (CVS/SVN/VSS/etc.).
Finally, you can just directly connect to Visual Source Safe. This MSKB article has some good information and background to go through, while this Office Online article is designed for getting you up and running.
Ultimately, I would suggest against taking the code out of Access if at all possible. Assuming the VBA editor is your primary development environment, you'll be adding extra steps to your development process that cannot easily be automated. Every change you make will need to be manually exported, diff'd, and stored, and there is no Application.OnCompile event that you could use to export the changes. Even tougher, you'll have to manually import all changed source files from other developers when they do checkins.
I use the code below to extract the vba code from Excel files, you may be able to modify this to extract from Access.
Sub ExtractVBACode(strSource, objFSO, strExportPath, objLogFile)
Dim objExcel
Dim objWorkbook
Dim objVBComponent
Dim strFileSuffix
Dim strExportFolder
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = true
Set objWorkbook = objExcel.Workbooks.Open(Trim(strSource))
strExportFolder = strExportPath & objFSO.GetBaseName(objWorkbook.Name)
If Not objFSO.FolderExists(strExportFolder) Then
objFSO.CreateFolder(strExportFolder)
End If
For Each objVBComponent In objWorkbook.VBProject.VBComponents
Select Case objVBComponent.Type
Case vbext_ct_ClassModule, vbext_ct_Document
strFileSuffix = ".cls"
Case vbext_ct_MSForm
strFileSuffix = ".frm"
Case vbext_ct_StdModule
strFileSuffix = ".bas"
Case Else
strFileSuffix = ""
End Select
If strFileSuffix <> "" Then
On Error Resume Next
Err.Clear
objVBComponent.Export strExportFolder & "\" & objVBComponent.Name & strFileSuffix
If Err.Number <> 0 Then
objLogFile.WriteLine ("Failed to export " & strExportFolder & "\" & objVBComponent.Name & strFileSuffix)
Else
objLogFile.WriteLine ("Export Successful: " & strExportFolder & "\" & objVBComponent.Name & strFileSuffix)
End If
On Error Goto 0
End If
Next
objExcel.DisplayAlerts = False
objExcel.Quit
End Sub
Can you extract the forms as XML perhaps?
I've struggled with this same problem. I originally wrote code very much like the existing answer. The trick is to get all of your modules onto the file system, but that method has some drawbacks. Going that route, you can get your forms and reports out of the VBA Projects, but you can't get them back in. So, I created a library as part of our Rubberduck VBE Add-in. The library I wrote takes care of importing and exporting all of your code to/from the VBA project to/from the repository as you seemlessly push, pull, and commit. It's a free and open source project, so feel free to download and install the latest version.
Here is an example of how the library is used. I'll be adding actual integration with the VBA editor in a future release.
Dim factory As New Rubberduck.SourceControlClassFactory
Dim repo As Rubberduck.IRepository
Dim git As ISourceControlProvider
Dim xl As New Excel.Application
xl.Visible = true
Dim wb As Excel.Workbook
Set wb = xl.Workbooks.Open("C:\Path\to\workbook.xlsm")
' create class instances to work with
Set repo = factory.CreateRepository(wb.VBProject.Name, "C:\Path\to\local\repository\SourceControlTest", "https://github.com/ckuhn203/SourceControlTest.git")
Set git = factory.CreateGitProvider(wb.VBProject, repo, "userName", "passWord")
' Create new branch to modify.
git.CreateBranch "NewBranchName"
' It is automatically checked out.
Debug.Print "Current Branch: " & git.CurrentBranch
' add a new standard (.bas) code module and a comment to that file
wb.VBProject.VBComponents.Add(vbext_ct_StdModule).CodeModule.AddFromString "' Hello There"
' add any new files to tracking
Dim fileStat As Rubberduck.FileStatusEntry
For Each fileStat In git.Status
' fileStat.FileStatus is a bitwise enumeration, so we use bitwise AND to test for equality here
If fileStat.FileStatus And Rubberduck.FileStatus.Added Then
git.AddFile fileStat.FilePath
End If
Next
git.Commit "commit all modified files"
' Revert the last commit, throwing away the changes we just made.
git.Revert