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
+}