diff --git a/Kill Process.alfredworkflow b/Kill Process.alfredworkflow index b2a3870..a6d17cd 100644 Binary files a/Kill Process.alfredworkflow and b/Kill Process.alfredworkflow differ diff --git a/current-version.json b/current-version.json index 08aacfa..06a68a4 100644 --- a/current-version.json +++ b/current-version.json @@ -1,5 +1,5 @@ { - "version": 1.21, + "version": 1.30, "download_url": "https://github.com/nathangreenstein/alfred-process-killer/blob/master/Kill%20Process.alfredworkflow?raw=true", "description": "New icon with higer visibility against black backgrounds (thanks to @sudopeople)." -} \ No newline at end of file +} diff --git a/script.rb b/script.rb deleted file mode 100644 index d71ce68..0000000 --- a/script.rb +++ /dev/null @@ -1,54 +0,0 @@ -# Type a query to test with here. -# !!!!! Comment this line out when pasting into alfred preferences. -theQuery = "chr" -# Grab the query that the user typed (this is provided by Alfred). -# !!!!! Uncomment this line when pasting into Alfred Preferences. -#theQuery = "{query}" -# Search the query string for an argument filter (in the form of 'process:arg'). -argsQuery = nil -if theQuery.include? ":" - theQuery, argsQuery = theQuery.split(":") -end -# Assemble an array of each matching process. It will contain the process's path and percent CPU usage. -# The -A flag shows all processes. The -o pid, -o %cpu, and -o comm show only the process's PID, CPU usage and path, respectively. -# Grep for processes whose name contains the query. The regex isolates the name by only searching characters after the last slash in the path. -# The -i flag ignores case. -processes = `ps -A -o pid -o %cpu -o comm | grep -i [^/]*#{Regexp.quote(theQuery)}[^/]*$`.split("\n") -# Start the XML string that will be sent to Alfred. This just uses strings to avoid dependencies. -xmlString = "\n\n" -processes.each do | process | - # Extract the PID, CPU usage, and path from the line (lines are in the form of `123 12.3 /path/to/process`). - processId, processCpu, processPath = process.match(/(\d+)\s+(\d+[\.|\,]\d+)\s+(.*)/).captures - # If an argument filter has been specified, get the arguments and search for the filter. - matchedArgs = [] - if argsQuery != nil - # Get the executable path and arguments for this process. Make an array with each argument that matches the search. - matchedArgs = `ps -p #{processId} -o command`.scan(/\s+-{1,2}[^\s]*#{Regexp.quote(argsQuery)}[^\s]*/i) - if matchedArgs.length < 1 - next - end - end - # Use the same expression as before to isolate the name of the process. - processName = processPath.match(/[^\/]*#{theQuery}[^\/]*$/i) - # Search for an application bundle in the path to the process. - iconValue = processPath.match(/.*?\.app\//) - # The icon type sent to Alfred is 'fileicon' (taken from a file). This assumes that a .app was found. - iconType = "fileicon" - # If no .app was found, use OS X's generic 'executable binary' icon. - # An empty icon type tells Alfred to load the icon from the file itself, rather than loading the file type's icon. - if !iconValue - iconValue = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ExecutableBinaryIcon.icns" - iconType = "" - end - # Assemble this item's XML string for Alfred. See http://www.alfredforum.com/topic/5-generating-feedback-in-workflows/ - thisXmlString = "\t - #{processName}#{matchedArgs.join(" ")} - #{processCpu}% CPU @ #{processPath} - #{iconValue} - \n" - # Append this process's XML string to the global XML string. - xmlString += thisXmlString -end -# Finish off and echo the XML string to Alfred. -xmlString += "" -puts xmlString \ No newline at end of file diff --git a/search_processes.rb b/search_processes.rb new file mode 100755 index 0000000..726b570 --- /dev/null +++ b/search_processes.rb @@ -0,0 +1,85 @@ +#!/usr/bin/env ruby + +class String + # See https://www.unicode.org/versions/Unicode15.0.0/UnicodeStandard-15.0.pdf#page=355 + COMBINING_DIACRITICS = [*0x1DC0..0x1DFF, *0x0300..0x036F, *0xFE20..0xFE2F].pack('U*') + + def removeaccents + self + .unicode_normalize(:nfd) # Decompose characters + .tr(COMBINING_DIACRITICS, '') + .unicode_normalize(:nfc) # Recompose characters + end +end + +# ======================================== + +# Type a query to test with here. +# theQuery = "chröme" + +# Comment this line if you are testing the script +theQuery = ARGV.join(" ") + +# Search the query string for an argument filter (in the form of 'process:arg'). +argsQuery = nil +if theQuery.include? ":" + theQuery, argsQuery = theQuery.split(":") +end + +# Make sure that searching for "Übersicht" matches "Ubersicht" +theQuery = theQuery.removeaccents + +# Get list of processes, and skip the first entry (headers) +psOutput = `ps -A -o pid -o %cpu -o comm | tail -n +2` +psOutputFiltered = psOutput.removeaccents + +# 29278 0.0 Core Audio Driver (NMAudioMic.driver) +processes = psOutputFiltered.scan(/^\s*\d+\s+(?:\d+[\.|\,]\d+)\s+[^\n]*#{Regexp.quote(theQuery)}[^\n]*$/im) + +# Start the XML string that will be sent to Alfred. This just uses strings to avoid dependencies. +xmlString = "\n\n" + +# Only iterate over the first 20 matched processes for performance reasons +processes.first(20).each do | process | + processId = process.match(/^\s*(\d+)\s+[^\n]+$/m).captures.first + + # psOutput has the original name containing diacritics (e.g. Übersicht instead of Ubersicht) + processCpu, processPath, processName = psOutput.match(/^\s*#{processId}\s+(\d+[\.|\,]\d+)\s+([^\n]*?\/?([^\n\/]+))$/im).captures + + # If an argument filter has been specified, get the arguments and search for the filter. + matchedArgs = [] + + if argsQuery != nil + # Get the executable path and arguments for this process. Make an array with each argument that matches the search. + matchedArgs = `ps -p #{processId} -o command`.scan(/\s+-{1,2}[^\s]*#{Regexp.quote(argsQuery)}[^\s]*/i) + + if matchedArgs.length < 1 + next + end + end + # Search for an application bundle in the path to the process. + iconValue = processPath.match(/.*?\.app\//) + + # The icon type sent to Alfred is 'fileicon' (taken from a file). This assumes that a .app was found. + iconType = "fileicon" + + # If no .app was found, use OS X's generic 'executable binary' icon. + # An empty icon type tells Alfred to load the icon from the file itself, rather than loading the file type's icon. + if !iconValue + iconValue = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ExecutableBinaryIcon.icns" + iconType = "" + end + + # Assemble this item's XML string for Alfred. See http://www.alfredforum.com/topic/5-generating-feedback-in-workflows/ + thisXmlString = "\t + #{processName}#{matchedArgs.join(" ")} + #{processCpu}% CPU @ #{processPath} + #{iconValue} + \n" + # Append this process's XML string to the global XML string. + xmlString += thisXmlString +end + +# Finish off and echo the XML string to Alfred. +xmlString += "" +puts xmlString diff --git a/update.json b/update.json index 06b6017..cf73980 100644 --- a/update.json +++ b/update.json @@ -1,4 +1,4 @@ { - "version": 1.21, + "version": 1.30, "remote_json": "https://raw.github.com/nathangreenstein/alfred-process-killer/master/current-version.json" -} \ No newline at end of file +}