Last active
May 19, 2021 20:24
-
-
Save hepcat72/3319f03f3b9e75ad2fa6e7f3d63c690b to your computer and use it in GitHub Desktop.
Automator services for frequent bioinformatics tasks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--What is this: This is an applescript to use in an automator service that allows you to get the nucleotide and alignment length of a sequence, along with stats on the numbers of individual characters. | |
--Purpose: Determine the length of a selected nucleotide and alignment string in any application. | |
--Installation: Create an Automator service, paste this code into a "Run AppleScript" action, and save. | |
--How to use it: 1. Select a nucleotide string (newlines, numbers, spaces, and any other character are allowed). 2. Right-click the selection and select this service. | |
--Author: Robert Leach, Genomics Group, Princeton, [email protected] | |
--Note, this counts "DNA characters" | |
on run {input, parameters} | |
tell application "System Events" | |
set _appname to name of first process whose frontmost is true | |
end tell | |
set msg to countNucleotides(input as string) | |
tell application _appname | |
display alert "" & msg | |
end tell | |
return input | |
end run | |
on countNucleotides(dnaStr) | |
set astid to AppleScript's text item delimiters | |
set AppleScript's text item delimiters to "A" | |
set aCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "T" | |
set tCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "G" | |
set gCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "C" | |
set cCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "B" | |
set bCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "D" | |
set dCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "H" | |
set hCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "V" | |
set vCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "R" | |
set rCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "Y" | |
set yCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "K" | |
set kCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "M" | |
set mCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "S" | |
set sCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "W" | |
set wCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "N" | |
set nCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "-" | |
set gapCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to astid | |
set seqTotal to aCount + tCount + gCount + cCount + bCount + dCount + hCount + vCount + rCount + yCount + kCount + mCount + sCount + wCount + nCount | |
set alnTotal to seqTotal + gapCount | |
set realTotal to aCount + tCount + gCount + cCount | |
set ambigTotal to seqTotal - realTotal | |
set statsstr to "Sequence length: " & (seqTotal as string) & " | |
Alignment length: " & (alnTotal as string) & " | |
Discrete Nucleotides: " & (realTotal as string) & " | |
Ambiguous Nucleotides: " & (ambigTotal as string) & " | |
Breakdown: | |
A " & aCount & " | |
T " & tCount & " | |
G " & gCount & " | |
C " & cCount & " | |
" | |
if bCount > 0 then | |
set statsstr to statsstr & " B " & bCount & " | |
" | |
end if | |
if dCount > 0 then | |
set statsstr to statsstr & " D " & dCount & " | |
" | |
end if | |
if hCount > 0 then | |
set statsstr to statsstr & " H " & hCount & " | |
" | |
end if | |
if vCount > 0 then | |
set statsstr to statsstr & " V " & vCount & " | |
" | |
end if | |
if rCount > 0 then | |
set statsstr to statsstr & " R " & rCount & " | |
" | |
end if | |
if yCount > 0 then | |
set statsstr to statsstr & " Y " & yCount & " | |
" | |
end if | |
if kCount > 0 then | |
set statsstr to statsstr & " K " & kCount & " | |
" | |
end if | |
if mCount > 0 then | |
set statsstr to statsstr & " M " & mCount & " | |
" | |
end if | |
if sCount > 0 then | |
set statsstr to statsstr & " S " & sCount & " | |
" | |
end if | |
if wCount > 0 then | |
set statsstr to statsstr & " W " & wCount & " | |
" | |
end if | |
if nCount > 0 then | |
set statsstr to statsstr & " N " & nCount & " | |
" | |
end if | |
if gapCount > 0 then | |
set statsstr to statsstr & " - " & gapCount & " | |
" | |
end if | |
return (statsstr) | |
end countNucleotides |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--What is this: This is an applescript to use in an automator service that allows you to get the length of any sequence, not including whitespace characters. | |
--Purpose: Determine the length of a selected amino acid or any other pseudo-sequence string in any application. | |
--Installation: Create an Automator service, paste this code into a "Run AppleScript" action, and save. | |
--How to use it: 1. Select a sequence string. 2. Right-click the selection and select this service. | |
--Author: Robert Leach, Genomics Group, Princeton, [email protected] | |
--Note, this counts "non-whitespace characters", i.e. everything except space, tab, newline, & carriage return | |
on run {input, parameters} | |
tell application "System Events" | |
set _appname to name of first process whose frontmost is true | |
end tell | |
set selText to item 1 of input as text | |
set AppleScript's text item delimiters to {space, tab, linefeed, return} | |
set selText to text items of selText | |
set AppleScript's text item delimiters to {} | |
set selText to selText as string | |
set character_count to count characters of selText | |
tell application _appname | |
display alert "" & character_count & " characters" | |
end tell | |
return input | |
end run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--What is this: This is an applescript to use in an automator service that allows you to get the most likely barcode combinations from a series of fastq files. It counts index sequences and looks for an order of magnitude jump in thos counts to guess the barcodes. | |
--Purpose: Determine the barcodes necessary to split fastq files by sample. | |
--Installation: Create an Automator service, select "Service receives selected [files of folders]", paste this code into a "Run AppleScript" action, and save as "Guess Barcodes.workflow". | |
--How to use it: 1. Right-click a fastq file and select this service ("Guess Barcodes"). 2. If no barcodes were found, click the "Edit Params" button and follow instructions | |
--Author: Robert Leach, Genomics Group, Princeton, [email protected] | |
--Version: 2.1 (added a setting for 5' or 3' results only and tweaked the order of magnitude threshold to be slightly less stringent) | |
--Version History: | |
-- V2.0 Added the ability to count barcode combinations. | |
-- V1.1 fixed an issue with max_barcodes being 0 not working as intended. | |
-- V1.0 handled fastq files independently. | |
on run {input, parameters} | |
set barcode_length to 8 | |
set max_barcodes to 100 | |
set check_n_seqs to 100000 --Set to 0 to check all or about 100000 to guess based on first million reads | |
set show_max to 0 --Set to 1 to show max_barcodes per file or 0 to only show the guessed barcodes | |
set barcodes_at_end to 0 | |
set done to false | |
set fastqFiles to {} | |
set validExtensions to {"fq", "fastq", "fastqsanger"} | |
tell application "Finder" | |
set delims to AppleScript's text item delimiters | |
set AppleScript's text item delimiters to "." | |
repeat with fqfile in input | |
set theEXT to last item of (text items of ((get name of (fqfile)) as text)) | |
if theEXT is in validExtensions then | |
set the end of fastqFiles to fqfile | |
else | |
display dialog "Extension " & ((name extension of (file fqfile)) as string) & " is not in validExtensions" | |
end if | |
end repeat | |
set AppleScript's text item delimiters to delims | |
end tell | |
if (count fastqFiles) is equal to 0 then | |
display dialog "Please select a file with a .fq, .fastq, or .fastqsanger extension" | |
return | |
end if | |
repeat while done is false | |
set barcodes to my getBarcodes(barcode_length, max_barcodes, check_n_seqs, show_max, fastqFiles, barcodes_at_end) | |
tell application "System Events" | |
set response to (display dialog "Educated barcode guesses:" default answer (barcodes as string) buttons {"Edit Params", "OK"} default button 1 with title "Barcodes") | |
end tell | |
if (the button returned of response) is "OK" then | |
set done to true | |
else | |
set {barcode_length, max_barcodes, check_n_seqs, show_max, barcodes_at_end} to my displayMultiDialog("Edit Barcode Search Parameters", "Edit the parameters that were last used on each line below. (Barcodes are determined by abundance - only the most abundant are considered. The cutoff selected is where the abundance jumps by an order of magnitude.)", {"• Barcode Length", "• Max Barcodes to evaluate (0 = all)", "• Number of reads to process", "• Show all considered barcodes (0=No, 1=Yes)", "• Barcodes at 3' end (0=No, 1=Yes)"}, {barcode_length as string, max_barcodes as string, check_n_seqs as string, show_max as string, barcodes_at_end as string}) | |
end if | |
end repeat | |
end run | |
on getBarcodes(barcode_length, max_barcodes, check_n_seqs, show_max, fqfiles, barcodes_at_end) | |
set check_n_lines to check_n_seqs * 4 | |
set limit_command to "tail -n " & max_barcodes | |
if max_barcodes < 1 then | |
set limit_command to "cat" | |
end if | |
tell application "Finder" | |
set filenames to {} | |
set paste_command to "paste" | |
repeat with fqfile in fqfiles | |
set the end of filenames to name of fqfile | |
if check_n_seqs < 1 then | |
if (barcodes_at_end as integer) is equal to 0 then | |
set paste_command to paste_command & " <(cat " & ((quoted form of (POSIX path of fqfile)) as string) & " | awk '(NR - 2) % 4 == 0' | perl -ne 'chomp;print(substr($_,0," & (barcode_length as string) & "),qq(\\n))')" | |
else | |
set paste_command to paste_command & " <(cat " & ((quoted form of (POSIX path of fqfile)) as string) & " | awk '(NR - 2) % 4 == 0' | perl -ne 'chomp;print(substr($_,-" & (barcode_length as string) & "),qq(\\n))')" | |
end if | |
else | |
if (barcodes_at_end as integer) is equal to 0 then | |
set paste_command to paste_command & " <(head -n " & check_n_lines & " " & ((quoted form of (POSIX path of fqfile)) as string) & " | awk '(NR - 2) % 4 == 0' | perl -ne 'chomp;print(substr($_,0," & (barcode_length as string) & "),qq(\\n))')" | |
else | |
set paste_command to paste_command & " <(head -n " & check_n_lines & " " & ((quoted form of (POSIX path of fqfile)) as string) & " | awk '(NR - 2) % 4 == 0' | perl -ne 'chomp;print(substr($_,-" & (barcode_length as string) & "),qq(\\n))')" | |
end if | |
end if | |
end repeat | |
if (barcodes_at_end as integer) is equal to 0 then | |
set barcodes to "5' barcodes for files:" & return & return | |
else | |
set barcodes to "3' barcodes for files:" & return & return | |
end if | |
set barcodes to barcodes & tab & my join(return & tab, filenames) & ":" & return & "----------" & return & return | |
set barcodes to barcodes & (do shell script "/bin/bash -s <<'EOF'" & linefeed & paste_command & " | sort | uniq -c | sort -n | " & limit_command & " | perl -e '$p=0;$o=0;while(<STDIN>){if(/(\\d+)/){$v=$1;if($o>0 && $v>(($o>10?$o-10:$o)*10)){$p=1;if(" & (show_max as string) & "){print(qq(\\n))}}s/\\s*(\\d+)\\s*(.+)\\s*/$2\\t$1\\n/;print if($p || " & (show_max as string) & ");$o=$v;}}if(!$p && !" & (show_max as string) & "){print(qq(No barcodes found. Try Editing params.))}'" & linefeed & "EOF") & return & return | |
end tell | |
end getBarcodes | |
on displayMultiDialog(mytitle, myPrompt, valuePrompts, default_vals) | |
return (inputItems for valuePrompts given title:mytitle, prompt:myPrompt, defaults:default_vals) | |
end displayMultiDialog | |
to inputItems for someItems given title:theTitle, prompt:thePrompt, defaults:theDefaults | |
(* | |
displays a dialog for multiple item entry - a carriage return is used between each input item | |
for each item in someItems, a line of text is displayed in the dialog and a line is reserved for the input | |
the number of items returned are padded or truncated to match the number of items in someItems | |
to fit the size of the dialog, items should be limited in length (~30) and number (~15) | |
parameters - someItems [list/integer]: a list or count of items to get from the dialog | |
theTitle [boolean/text]: use a default or the given dialog title | |
thePrompt [boolean/text]: use a default or the given prompt text | |
returns [list]: a list of the input items | |
*) | |
if thePrompt is in {true, false} then -- "with" or "without" prompt | |
if thePrompt then | |
set thePrompt to "Input the following items:" & return & return -- default | |
else | |
set thePrompt to "" | |
end if | |
else -- fix up the prompt a bit | |
set thePrompt to thePrompt & return & return | |
end if | |
if theTitle is in {true, false} then if theTitle then -- "with" or "without" title | |
set theTitle to "Multiple Input Dialog" -- default | |
else | |
set theTitle to "" | |
end if | |
if theDefaults is in {false} then -- "with" or "without" prompt | |
set theDefaults to {} | |
end if | |
set theDefaultCount to (count theDefaults) | |
if class of someItems is integer then -- no item list | |
set {theCount, someItems} to {someItems, ""} | |
if thePrompt is not "" then set thePrompt to text 1 thru -2 of thePrompt | |
else | |
set theCount to (count someItems) | |
end if | |
if theCount is less than 1 then error "inputItems handler: empty input list" | |
set {theItems, theInput} to {{}, {}} | |
if theDefaultCount is greater than theCount then error "inputItems handler: Too many default values" | |
repeat with itemNum from 1 to theCount -- set the number of lines in the input and the defaults | |
if itemNum is greater than theDefaultCount then | |
set the end of theInput to "" | |
if theDefaultCount is greater than 0 then | |
set item itemNum of someItems to (item itemNum of someItems) & " [\"\"]" | |
end if | |
else | |
set the end of theInput to item itemNum of theDefaults as string | |
set item itemNum of someItems to (item itemNum of someItems) & " [\"" & (item itemNum of theDefaults) & "\"]" | |
end if | |
end repeat | |
set {tempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return} | |
set {someItems, theInput} to {someItems as text, theInput as text} | |
set AppleScript's text item delimiters to tempTID | |
set theInput to paragraphs of text returned of (display dialog thePrompt & someItems with title theTitle default answer theInput) | |
repeat with anItem from 1 to theCount -- pad/truncate entered items | |
try | |
set the end of theItems to (item anItem of theInput) | |
on error | |
set the end of theItems to "" | |
end try | |
end repeat | |
return theItems | |
end inputItems | |
on join(myDelimiter, myList) | |
set astid to AppleScript's text item delimiters | |
set AppleScript's text item delimiters to myDelimiter | |
set joinedString to myList as text | |
set AppleScript's text item delimiters to astid | |
return joinedString | |
end join |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--What is this: This is an applescript to use in an automator service that allows you to get the reverse complement of selected DNA sequence in a resulting dialog window. | |
--Purpose: To quickly get the reverse complement of a selected sequence in any app. | |
--Installation: Create an Automator service, paste this code into a "Run AppleScript" action, and save. | |
--How to use it: 1. Select the sequence you wish to see the reverse complement of. 2. Right-click the selection and select this service. | |
--Author: Robert Leach, Genomics Group, Princeton, [email protected] | |
on run {input, parameters} | |
tell application "System Events" | |
set _appname to name of first process whose frontmost is true | |
end tell | |
set msg to reverseComplement(input as string) | |
tell application _appname | |
display dialog "Reverse Complement:" default answer msg buttons {"OK"} default button 1 with title "Reverse Complement" | |
end tell | |
return input | |
end run | |
on reverseComplement(dnaStr) | |
set revStr to reverse of characters of dnaStr as text | |
set revCompStr to complement(revStr) | |
return (revCompStr) | |
end reverseComplement | |
on complement(dnaStr) | |
set str_pos to 1 | |
set len to length of dnaStr | |
set comp to "" | |
repeat while str_pos ≤ len | |
set nt to text str_pos thru str_pos of dnaStr | |
set comp to comp & complementNt(nt) | |
set str_pos to str_pos + 1 | |
end repeat | |
return (comp) | |
end complement | |
on complementNt(nt) | |
set compNt to nt | |
if nt is equal to "A" then | |
return ("T") | |
else if nt is equal to "a" then | |
return ("t") | |
else if nt is equal to "T" then | |
return ("A") | |
else if nt is equal to "t" then | |
return ("a") | |
else if nt is equal to "G" then | |
return ("C") | |
else if nt is equal to "g" then | |
return ("c") | |
else if nt is equal to "C" then | |
return ("G") | |
else if nt is equal to "c" then | |
return ("g") | |
else if nt is equal to "B" then | |
return ("V") | |
else if nt is equal to "b" then | |
return ("v") | |
else if nt is equal to "D" then | |
return ("H") | |
else if nt is equal to "d" then | |
return ("h") | |
else if nt is equal to "H" then | |
return ("D") | |
else if nt is equal to "h" then | |
return ("d") | |
else if nt is equal to "V" then | |
return ("B") | |
else if nt is equal to "v" then | |
return ("b") | |
else if nt is equal to "R" then | |
return ("Y") | |
else if nt is equal to "r" then | |
return ("y") | |
else if nt is equal to "Y" then | |
return ("R") | |
else if nt is equal to "y" then | |
return ("r") | |
else if nt is equal to "K" then | |
return ("M") | |
else if nt is equal to "k" then | |
return ("m") | |
else if nt is equal to "M" then | |
return ("K") | |
else if nt is equal to "m" then | |
return ("k") | |
end if | |
--Don't need to do S, W, or N, because they complement themselves | |
--All other characters such as white spaces, numbers, gaps or other stuff will just be returned as-is without error or warning | |
return (compNt) | |
end complementNt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--Installation: Create an Automator service, paste this code into a "Run AppleScript" action, and save. | |
--How to use it: 1. Copy a number indicating the length you want the selection to be. 2. Select the region of text where you want the copied length to be selected. 3. Right-click the selection and select this service. | |
--NOTES: | |
--If the contents of the clipboard is not a number, you'll be prompted to enter a length. | |
--If the selected text is in Terminal.app, the modified selection will display in a dialog window (because the arrow keys are used for the selection modification and that doesn't work in Terminal). Also, if the target selection length is longer than the current selection, an error about selection length will be displayed. | |
--If input is not supplied, this script will backup the current clipboard, copy the current selection to get the currently selected text, then restore the clipboard. | |
on run {input, parameters} | |
try | |
set debug to false | |
if input's class is not list then | |
set input to (my getHighlight(debug)) | |
end if | |
tell application "System Events" | |
--See if the clipboard has a number in it to use for the selection length | |
set checkClipboard to the clipboard as text | |
if my isNumString(checkClipboard) then | |
set n to checkClipboard as integer | |
else | |
--Get the name of the frontmost application so we can bring the front window back into focus after the dialog window goes away (which surprisingly, is not the default behavior) | |
set curProc to (name of first process whose frontmost is true) | |
set n to my getintvalue() | |
--And this is the only trick I've found to bring any window in an app back into focus | |
do shell script "open -a '" & (curProc as string) & "'" | |
delay 0.2 | |
end if | |
set {selText, nt_count} to (my selectAtLeastAln((input as string), (n as integer), debug)) | |
--Exit if an empty string was returned (indicating an error) | |
if selText is "" then | |
return | |
end if | |
--Estimate/guess whether it will be quicker to shrink the selection from the end or grow the selection from the beginning | |
set shrinkit to ((nt_count - n) < n) | |
--Figure out whether the selection must be lengthened or shrunk | |
if nt_count is equal to 0 or n is greater than nt_count then | |
display dialog "The selection length must be greater than the number of characters to select" | |
return | |
end if | |
--See if we're in Terminal | |
set isTerminal to ((name of first process where it is frontmost) as string) is equal to "Terminal" | |
if isTerminal is true then | |
ignoring application responses | |
display dialog "Length " & n & " is selected below:" default answer selText buttons {"OK"} default button 1 with title "Selected Character Position" | |
end ignoring | |
end if | |
if shrinkit is false then | |
key code 123 | |
set str_pos to 1 | |
set nt_count to 0 | |
repeat while nt_count < n | |
key code 124 using {shift down} | |
set nt to text str_pos thru str_pos of selText | |
if (my countAlignChars(nt)) > 0 then | |
set nt_count to nt_count + 1 | |
end if | |
set str_pos to str_pos + 1 | |
end repeat | |
else | |
--Trick to make sure arrow presses affect the right side of the selection instead of the left | |
set character_count to count characters of selText | |
key code 124 using {shift down} | |
key code 123 using {shift down} | |
if (count characters of selText) < character_count then | |
key code 124 using {shift down} | |
end if | |
set str_pos to character_count | |
set nt to text str_pos thru str_pos of selText | |
repeat while nt_count > n or (my countAlignChars(nt)) < 1 | |
key code 123 using {shift down} | |
if (my countAlignChars(nt)) > 0 then | |
set nt_count to nt_count - 1 | |
end if | |
set str_pos to str_pos - 1 | |
set nt to text str_pos thru str_pos of selText | |
end repeat | |
end if | |
delay 1 | |
end tell | |
on error errstr | |
display dialog errstr | |
end try | |
end run | |
property mytitle : "Length of text to select" | |
-- I am asking the user to provide an integer | |
-- In case the user cancels the dialog, I return «missing value» | |
on getintvalue() | |
set dlgmsg to "How many characters would you like to select?:" | |
try | |
display dialog dlgmsg default answer "1" buttons {"Cancel", "Enter"} default button 2 with title mytitle | |
on error | |
-- User canceled | |
return missing value | |
end try | |
set dlgresult to result | |
set usrinput to text returned of dlgresult | |
-- the user did not enter anything... | |
if usrinput is "" then | |
my getintvalue() | |
else | |
-- let's check if the user entered numbers only | |
set nums to {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"} | |
set invalidchars to "" | |
repeat with char in usrinput | |
if char is not in nums then | |
set invalidchars to invalidchars & char & space | |
end if | |
end repeat | |
-- we found invalid characters | |
if invalidchars is not "" then | |
set errmsg to "We found the following characters in the given input. Please enter numbers only." & return & return & invalidchars & return | |
my dsperrmsg(errmsg, "--") | |
my getintvalue() | |
else | |
-- let's try to transform the user input into an integer | |
try | |
set intvalue to usrinput as integer | |
return intvalue | |
on error | |
set errmsg to "We could not coerce the given input into an integer:" & return & return & usrinput & return | |
my dsperrmsg(errmsg, "--") | |
my getintvalue() | |
end try | |
end if | |
end if | |
end getintvalue | |
-- I am displaying error messages to the user | |
on dsperrmsg(errmsg, errnum) | |
tell me | |
activate | |
display dialog errmsg & " (" & errnum & ")" buttons {"OK"} default button 1 with title mytitle with icon stop | |
end tell | |
end dsperrmsg | |
-- isNumString :: String -> Bool | |
on isNumString(s) | |
try | |
if class of s is string then | |
set c to class of (s as number) | |
c is real or c is integer | |
else | |
false | |
end if | |
on error | |
false | |
end try | |
end isNumString | |
on getHighlight(debug) | |
--Save the current contents of the clipboard | |
try | |
set theSpare to the clipboard --as text | |
on error | |
set response to (display dialog "Warning: The contents of the clipboard will be lost." buttons {"Cancel", "OK"}) | |
if button returned of response is "OK" then | |
set theSpare to "" | |
end if | |
end try | |
set the clipboard to "" | |
--Declare the variable we're going to return | |
set selecTxt to "" | |
tell application "System Events" | |
--Initiate the copy | |
keystroke "c" using {command down} | |
--Wait up to 2 seconds for the copy to finish | |
set done to "no" | |
set waitnum to 0 | |
set waitInterval to 0.02 | |
set maxwaits to 100 | |
--Repeat while the clipboard contents have not changed | |
repeat while done = "no" | |
--Get the contents of the clipboard | |
try | |
set selecTxt to the clipboard as text | |
end try | |
--See if we're done or need to wait | |
if waitnum is equal to maxwaits then | |
set done to "yes" | |
else if selecTxt is equal to "" then | |
delay waitInterval | |
set waitnum to waitnum + 1 | |
else | |
set done to "yes" | |
end if | |
end repeat | |
if debug is true then | |
try | |
display dialog "Copied text: " & (the clipboard as text) | |
end try | |
end if | |
end tell | |
--Restore the original clipboard contents | |
set the clipboard to theSpare --as record | |
if debug is true then | |
try | |
display dialog "The clipboard contents have been restored to " & (the clipboard as text) | |
end try | |
end if | |
--Return the highlighted text | |
return selecTxt | |
end getHighlight | |
on countAlignChars(dnaStr) | |
set astid to AppleScript's text item delimiters | |
set AppleScript's text item delimiters to "A" | |
set aCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "T" | |
set tCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "G" | |
set gCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "C" | |
set cCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "B" | |
set bCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "D" | |
set dCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "H" | |
set hCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "V" | |
set vCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "R" | |
set rCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "Y" | |
set yCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "K" | |
set kCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "M" | |
set mCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "S" | |
set sCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "W" | |
set wCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "N" | |
set nCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "-" | |
set gapCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to astid | |
set seqTotal to aCount + tCount + gCount + cCount + bCount + dCount + hCount + vCount + rCount + yCount + kCount + mCount + sCount + wCount + nCount | |
set alnTotal to seqTotal + gapCount | |
return (alnTotal as integer) | |
end countAlignChars | |
--Uses the down arrow to grab at least n characters of nucleotides and returns the newly selected string and the number of nucleotides it contains | |
on selectAtLeastAln(initial_str as string, n as integer, debug) | |
set cur_str to initial_str | |
set character_count to ((count characters of cur_str) as integer) | |
set last_character_count to 0 | |
set nt_count to ((my countAlignChars(cur_str)) as integer) | |
repeat while character_count > last_character_count and nt_count < n | |
--Add a line to the selection | |
tell application "System Events" to key code 125 using {shift down} | |
set cur_str to (my getHighlight(debug)) | |
set last_character_count to character_count | |
set character_count to ((count characters of cur_str) as integer) | |
set nt_count to (my countAlignChars(cur_str)) | |
end repeat | |
if nt_count < n then | |
display dialog "Error: Unable to select enough sequence. Please make sure to select more sequence than the target length (" & (n as string) & ")." | |
return ({"", 0}) | |
end if | |
return ({cur_str as string, nt_count as integer}) | |
end selectAtLeastAln |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--What is this: This is an applescript to use in an automator service that allows you to modify the length of a text selection to a value specified (either by a number on the clipboard or a number entered at a prompt). | |
--Purpose: The initial intent is to use this service to visualize a specific position in a DNA or protein string (although it currently assumes the string is solid sequence characters - a future *separate* version will count only relevant characters). | |
--Installation: Create an Automator service, paste this code into a "Run AppleScript" action, and save. | |
--How to use it: 1. Copy a number indicating the length you want the selection to be. 2. Select the region of text where you want the copied length to be selected. 3. Right-click the selection and select this service. | |
--Author: Robert Leach, Genomics Group, Princeton, [email protected] | |
--NOTES: | |
--If the contents of the clipboard is not a number, you'll be prompted to enter a length. | |
--If the selected text is in Terminal.app, the modified selection will display in a dialog window (because the arrow keys are used for the selection modification and that doesn't work in Terminal). Also, if the target selection length is longer than the current selection, the remainder will be filled in with N's (because this was originally made for DNA strings). | |
--If input is not supplied, this script will backup the current clipboard, copy the current selection to get the currently selected text, then restore the clipboard. | |
on run {input, parameters} | |
try | |
set debug to false | |
if input's class is not list then | |
set input to getHighlight(debug) | |
end if | |
tell application "System Events" | |
--See if the clipboard has a number in it to use for the selection length | |
set checkClipboard to the clipboard as text | |
if my isNumString(checkClipboard) then | |
set n to checkClipboard as integer | |
else | |
--Get the name of the frontmost application so we can bring the front window back into focus after the dialog window goes away (which surprisingly, is not the default behavior) | |
set curProc to (name of first process whose frontmost is true) | |
set n to my getintvalue() | |
--And this is the only trick I've found to bring any window in an app back into focus | |
do shell script "open -a '" & (curProc as string) & "'" | |
delay 0.2 | |
end if | |
--Check the length of the selected text passed in | |
set character_count to count characters of ((input as string) as string) | |
set lengthen to false | |
set mod_length to character_count - n | |
--Figure out whether the selection must be lengthened or shrunk | |
if character_count is equal to 0 or n is greater than character_count then | |
set lengthen to true | |
set mod_length to n - character_count | |
end if | |
--See if we're in Terminal | |
set isTerminal to ((name of first process where it is frontmost) as string) is equal to "Terminal" | |
if isTerminal is true then | |
if lengthen is true then | |
set substr to (input as string) | |
repeat mod_length times | |
set substr to substr & "N" | |
end repeat | |
else | |
set substr to text 1 thru n of (input as string) | |
set substr to substr & (text (n + 1) thru character_count of (input as string)) | |
end if | |
ignoring application responses | |
display dialog "Length " & n & " is selected below:" default answer substr buttons {"OK"} default button 1 with title "Selected Character Position" | |
end ignoring | |
end if | |
--Trick to make sure arrow presses affect the right side of the selection instead of the left | |
if not (character_count is equal to 0 or n is greater than character_count) then | |
key code 124 using {shift down} | |
key code 123 using {shift down} | |
key code 124 using {shift down} | |
end if | |
if lengthen is false and n is less than mod_length then | |
if character_count is greater than 0 then | |
key code 123 | |
end if | |
repeat n times | |
key code 124 using {shift down} | |
end repeat | |
else | |
repeat mod_length times | |
if lengthen is true then | |
key code 124 using {shift down} | |
else | |
key code 123 using {shift down} | |
end if | |
end repeat | |
end if | |
delay 1 | |
end tell | |
on error errstr | |
display dialog errstr | |
end try | |
end run | |
property mytitle : "Length of text to select" | |
-- I am asking the user to provide an integer | |
-- In case the user cancels the dialog, I return «missing value» | |
on getintvalue() | |
set dlgmsg to "How many characters would you like to select?:" | |
try | |
display dialog dlgmsg default answer "1" buttons {"Cancel", "Enter"} default button 2 with title mytitle | |
on error | |
-- User canceled | |
return missing value | |
end try | |
set dlgresult to result | |
set usrinput to text returned of dlgresult | |
-- the user did not enter anything... | |
if usrinput is "" then | |
my getintvalue() | |
else | |
-- let's check if the user entered numbers only | |
set nums to {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"} | |
set invalidchars to "" | |
repeat with char in usrinput | |
if char is not in nums then | |
set invalidchars to invalidchars & char & space | |
end if | |
end repeat | |
-- we found invalid characters | |
if invalidchars is not "" then | |
set errmsg to "We found the following characters in the given input. Please enter numbers only." & return & return & invalidchars & return | |
my dsperrmsg(errmsg, "--") | |
my getintvalue() | |
else | |
-- let's try to transform the user input into an integer | |
try | |
set intvalue to usrinput as integer | |
return intvalue | |
on error | |
set errmsg to "We could not coerce the given input into an integer:" & return & return & usrinput & return | |
my dsperrmsg(errmsg, "--") | |
my getintvalue() | |
end try | |
end if | |
end if | |
end getintvalue | |
-- I am displaying error messages to the user | |
on dsperrmsg(errmsg, errnum) | |
tell me | |
activate | |
display dialog errmsg & " (" & errnum & ")" buttons {"OK"} default button 1 with title mytitle with icon stop | |
end tell | |
end dsperrmsg | |
-- isNumString :: String -> Bool | |
on isNumString(s) | |
try | |
if class of s is string then | |
set c to class of (s as number) | |
c is real or c is integer | |
else | |
false | |
end if | |
on error | |
false | |
end try | |
end isNumString | |
on getHighlight(debug) | |
--Save the current contents of the clipboard | |
try | |
set theSpare to the clipboard --as text | |
on error | |
set response to (display dialog "Warning: The contents of the clipboard will be lost." buttons {"Cancel", "OK"}) | |
if button returned of response is "OK" then | |
set theSpare to "" | |
end if | |
end try | |
set the clipboard to "" | |
--Declare the variable we're going to return | |
set selecTxt to "" | |
tell application "System Events" | |
--Initiate the copy | |
keystroke "c" using {command down} | |
--Wait up to 2 seconds for the copy to finish | |
set done to "no" | |
set waitnum to 0 | |
set waitInterval to 0.02 | |
set maxwaits to 100 | |
--Repeat while the clipboard contents have not changed | |
repeat while done = "no" | |
--Get the contents of the clipboard | |
try | |
set selecTxt to the clipboard as text | |
end try | |
--See if we're done or need to wait | |
if waitnum is equal to maxwaits then | |
set done to "yes" | |
else if selecTxt is equal to "" then | |
delay waitInterval | |
set waitnum to waitnum + 1 | |
else | |
set done to "yes" | |
end if | |
end repeat | |
if debug is true then | |
try | |
display dialog "Copied text: " & (the clipboard as text) | |
end try | |
end if | |
end tell | |
--Restore the original clipboard contents | |
set the clipboard to theSpare --as record | |
if debug is true then | |
try | |
display dialog "The clipboard contents have been restored to " & (the clipboard as text) | |
end try | |
end if | |
--Return the highlighted text | |
return selecTxt | |
end getHighlight |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--Installation: Create an Automator service, paste this code into a "Run AppleScript" action, and save. | |
--How to use it: 1. Copy a number indicating the length you want the selection to be. 2. Select the region of text where you want the copied length to be selected. 3. Right-click the selection and select this service. | |
--NOTES: | |
--If the contents of the clipboard is not a number, you'll be prompted to enter a length. | |
--If the selected text is in Terminal.app, the modified selection will display in a dialog window (because the arrow keys are used for the selection modification and that doesn't work in Terminal). Also, if the target selection length is longer than the current selection, an error about selection length will be displayed. | |
--If input is not supplied, this script will backup the current clipboard, copy the current selection to get the currently selected text, then restore the clipboard. | |
on run {input, parameters} | |
try | |
set debug to false | |
if input's class is not list then | |
set input to (my getHighlight(debug)) | |
end if | |
tell application "System Events" | |
--See if the clipboard has a number in it to use for the selection length | |
set checkClipboard to the clipboard as text | |
if my isNumString(checkClipboard) then | |
set n to checkClipboard as integer | |
else | |
--Get the name of the frontmost application so we can bring the front window back into focus after the dialog window goes away (which surprisingly, is not the default behavior) | |
set curProc to (name of first process whose frontmost is true) | |
set n to my getintvalue() | |
--And this is the only trick I've found to bring any window in an app back into focus | |
do shell script "open -a '" & (curProc as string) & "'" | |
delay 0.2 | |
end if | |
set {selText, nt_count} to (my selectAtLeast((input as string), (n as integer), debug)) | |
--Exit if an empty string was returned (indicating an error) | |
if selText is "" then | |
return | |
end if | |
--Estimate/guess whether it will be quicker to shrink the selection from the end or grow the selection from the beginning | |
set shrinkit to ((nt_count - n) < n) | |
--Figure out whether the selection must be lengthened or shrunk | |
if nt_count is equal to 0 or n is greater than nt_count then | |
display dialog "The selection length must be greater than the number of characters to select" | |
return | |
end if | |
--See if we're in Terminal | |
set isTerminal to ((name of first process where it is frontmost) as string) is equal to "Terminal" | |
if isTerminal is true then | |
ignoring application responses | |
display dialog "Length " & n & " is selected below:" default answer selText buttons {"OK"} default button 1 with title "Selected Character Position" | |
end ignoring | |
end if | |
if shrinkit is false then | |
key code 123 | |
set str_pos to 1 | |
set nt_count to 0 | |
repeat while nt_count < n | |
key code 124 using {shift down} | |
set nt to text str_pos thru str_pos of selText | |
if (my countNucleotides(nt)) > 0 then | |
set nt_count to nt_count + 1 | |
end if | |
set str_pos to str_pos + 1 | |
end repeat | |
else | |
--Trick to make sure arrow presses affect the right side of the selection instead of the left | |
set character_count to count characters of selText | |
key code 124 using {shift down} | |
key code 123 using {shift down} | |
if (count characters of selText) < character_count then | |
key code 124 using {shift down} | |
end if | |
set str_pos to character_count | |
set nt to text str_pos thru str_pos of selText | |
repeat while nt_count > n or (my countNucleotides(nt)) < 1 | |
key code 123 using {shift down} | |
if (my countNucleotides(nt)) > 0 then | |
set nt_count to nt_count - 1 | |
end if | |
set str_pos to str_pos - 1 | |
set nt to text str_pos thru str_pos of selText | |
end repeat | |
end if | |
delay 1 | |
end tell | |
on error errstr | |
display dialog errstr | |
end try | |
end run | |
property mytitle : "Length of text to select" | |
-- I am asking the user to provide an integer | |
-- In case the user cancels the dialog, I return «missing value» | |
on getintvalue() | |
set dlgmsg to "How many characters would you like to select?:" | |
try | |
display dialog dlgmsg default answer "1" buttons {"Cancel", "Enter"} default button 2 with title mytitle | |
on error | |
-- User canceled | |
return missing value | |
end try | |
set dlgresult to result | |
set usrinput to text returned of dlgresult | |
-- the user did not enter anything... | |
if usrinput is "" then | |
my getintvalue() | |
else | |
-- let's check if the user entered numbers only | |
set nums to {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"} | |
set invalidchars to "" | |
repeat with char in usrinput | |
if char is not in nums then | |
set invalidchars to invalidchars & char & space | |
end if | |
end repeat | |
-- we found invalid characters | |
if invalidchars is not "" then | |
set errmsg to "We found the following characters in the given input. Please enter numbers only." & return & return & invalidchars & return | |
my dsperrmsg(errmsg, "--") | |
my getintvalue() | |
else | |
-- let's try to transform the user input into an integer | |
try | |
set intvalue to usrinput as integer | |
return intvalue | |
on error | |
set errmsg to "We could not coerce the given input into an integer:" & return & return & usrinput & return | |
my dsperrmsg(errmsg, "--") | |
my getintvalue() | |
end try | |
end if | |
end if | |
end getintvalue | |
-- I am displaying error messages to the user | |
on dsperrmsg(errmsg, errnum) | |
tell me | |
activate | |
display dialog errmsg & " (" & errnum & ")" buttons {"OK"} default button 1 with title mytitle with icon stop | |
end tell | |
end dsperrmsg | |
-- isNumString :: String -> Bool | |
on isNumString(s) | |
try | |
if class of s is string then | |
set c to class of (s as number) | |
c is real or c is integer | |
else | |
false | |
end if | |
on error | |
false | |
end try | |
end isNumString | |
on getHighlight(debug) | |
--Save the current contents of the clipboard | |
try | |
set theSpare to the clipboard --as text | |
on error | |
set response to (display dialog "Warning: The contents of the clipboard will be lost." buttons {"Cancel", "OK"}) | |
if button returned of response is "OK" then | |
set theSpare to "" | |
end if | |
end try | |
set the clipboard to "" | |
--Declare the variable we're going to return | |
set selecTxt to "" | |
tell application "System Events" | |
--Initiate the copy | |
keystroke "c" using {command down} | |
--Wait up to 2 seconds for the copy to finish | |
set done to "no" | |
set waitnum to 0 | |
set waitInterval to 0.02 | |
set maxwaits to 100 | |
--Repeat while the clipboard contents have not changed | |
repeat while done = "no" | |
--Get the contents of the clipboard | |
try | |
set selecTxt to the clipboard as text | |
end try | |
--See if we're done or need to wait | |
if waitnum is equal to maxwaits then | |
set done to "yes" | |
else if selecTxt is equal to "" then | |
delay waitInterval | |
set waitnum to waitnum + 1 | |
else | |
set done to "yes" | |
end if | |
end repeat | |
if debug is true then | |
try | |
display dialog "Copied text: " & (the clipboard as text) | |
end try | |
end if | |
end tell | |
--Restore the original clipboard contents | |
set the clipboard to theSpare --as record | |
if debug is true then | |
try | |
display dialog "The clipboard contents have been restored to " & (the clipboard as text) | |
end try | |
end if | |
--Return the highlighted text | |
return selecTxt | |
end getHighlight | |
on countNucleotides(dnaStr) | |
set astid to AppleScript's text item delimiters | |
set AppleScript's text item delimiters to "A" | |
set aCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "T" | |
set tCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "G" | |
set gCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "C" | |
set cCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "B" | |
set bCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "D" | |
set dCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "H" | |
set hCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "V" | |
set vCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "R" | |
set rCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "Y" | |
set yCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "K" | |
set kCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "M" | |
set mCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "S" | |
set sCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "W" | |
set wCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to "N" | |
set nCount to (count dnaStr's text items) - 1 | |
set AppleScript's text item delimiters to astid | |
set seqTotal to aCount + tCount + gCount + cCount + bCount + dCount + hCount + vCount + rCount + yCount + kCount + mCount + sCount + wCount + nCount | |
return (seqTotal as integer) | |
end countNucleotides | |
--Uses the down arrow to grab at least n characters of nucleotides and returns the newly selected string and the number of nucleotides it contains | |
on selectAtLeast(initial_str as string, n as integer, debug) | |
set cur_str to initial_str | |
set character_count to ((count characters of cur_str) as integer) | |
set last_character_count to 0 | |
set nt_count to ((my countNucleotides(cur_str)) as integer) | |
repeat while character_count > last_character_count and nt_count < n | |
--Add a line to the selection | |
tell application "System Events" to key code 125 using {shift down} | |
set cur_str to (my getHighlight(debug)) | |
set last_character_count to character_count | |
set character_count to ((count characters of cur_str) as integer) | |
set nt_count to (my countNucleotides(cur_str)) | |
end repeat | |
if nt_count < n then | |
display dialog "Error: Unable to select enough sequence. Please make sure to select more sequence than the target length (" & (n as string) & ")." | |
return ({"", 0}) | |
end if | |
return ({cur_str as string, nt_count as integer}) | |
end selectAtLeast |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--Installation: Create an Automator service, paste this code into a "Run AppleScript" action, and save. | |
--How to use it: 1. Copy a number indicating the length you want the selection to be. 2. Select the region of text where you want the copied length to be selected. 3. Right-click the selection and select this service. | |
--NOTES: | |
--If the contents of the clipboard is not a number, you'll be prompted to enter a length. | |
--If the selected text is in Terminal.app, the modified selection will display in a dialog window (because the arrow keys are used for the selection modification and that doesn't work in Terminal). Also, if the target selection length is longer than the current selection, an error about selection length will be displayed. | |
--If input is not supplied, this script will backup the current clipboard, copy the current selection to get the currently selected text, then restore the clipboard. | |
on run {input, parameters} | |
try | |
set debug to false | |
if input's class is not list then | |
set input to (my getHighlight(debug)) | |
end if | |
tell application "System Events" | |
--See if the clipboard has a number in it to use for the selection length | |
set checkClipboard to the clipboard as text | |
if my isNumString(checkClipboard) then | |
set n to checkClipboard as integer | |
else | |
--Get the name of the frontmost application so we can bring the front window back into focus after the dialog window goes away (which surprisingly, is not the default behavior) | |
set curProc to (name of first process whose frontmost is true) | |
set n to my getintvalue() | |
--And this is the only trick I've found to bring any window in an app back into focus | |
do shell script "open -a '" & (curProc as string) & "'" | |
delay 0.2 | |
end if | |
set {selText, nt_count} to (my selectAtLeastAln((input as string), (n as integer), debug)) | |
--Exit if an empty string was returned (indicating an error) | |
if selText is "" then | |
return | |
end if | |
--Estimate/guess whether it will be quicker to shrink the selection from the end or grow the selection from the beginning | |
set shrinkit to ((nt_count - n) < n) | |
--Figure out whether the selection must be lengthened or shrunk | |
if nt_count is equal to 0 or n is greater than nt_count then | |
display dialog "The selection length must be greater than the number of characters to select" | |
return | |
end if | |
--See if we're in Terminal | |
set isTerminal to ((name of first process where it is frontmost) as string) is equal to "Terminal" | |
if isTerminal is true then | |
ignoring application responses | |
display dialog "Length " & n & " is selected below:" default answer selText buttons {"OK"} default button 1 with title "Selected Character Position" | |
end ignoring | |
end if | |
if shrinkit is false then | |
key code 123 | |
set str_pos to 1 | |
set nt_count to 0 | |
repeat while nt_count < n | |
key code 124 using {shift down} | |
set nt to text str_pos thru str_pos of selText | |
if (my countSequenceChars(nt)) > 0 then | |
set nt_count to nt_count + 1 | |
end if | |
set str_pos to str_pos + 1 | |
end repeat | |
else | |
--Trick to make sure arrow presses affect the right side of the selection instead of the left | |
set character_count to count characters of selText | |
key code 124 using {shift down} | |
key code 123 using {shift down} | |
if (count characters of selText) < character_count then | |
key code 124 using {shift down} | |
end if | |
set str_pos to character_count | |
set nt to text str_pos thru str_pos of selText | |
repeat while nt_count > n or (my countSequenceChars(nt)) < 1 | |
key code 123 using {shift down} | |
if (my countSequenceChars(nt)) > 0 then | |
set nt_count to nt_count - 1 | |
end if | |
set str_pos to str_pos - 1 | |
set nt to text str_pos thru str_pos of selText | |
end repeat | |
end if | |
delay 1 | |
end tell | |
on error errstr | |
display dialog errstr | |
end try | |
end run | |
property mytitle : "Length of text to select" | |
-- I am asking the user to provide an integer | |
-- In case the user cancels the dialog, I return «missing value» | |
on getintvalue() | |
set dlgmsg to "How many characters would you like to select?:" | |
try | |
display dialog dlgmsg default answer "1" buttons {"Cancel", "Enter"} default button 2 with title mytitle | |
on error | |
-- User canceled | |
return missing value | |
end try | |
set dlgresult to result | |
set usrinput to text returned of dlgresult | |
-- the user did not enter anything... | |
if usrinput is "" then | |
my getintvalue() | |
else | |
-- let's check if the user entered numbers only | |
set nums to {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"} | |
set invalidchars to "" | |
repeat with char in usrinput | |
if char is not in nums then | |
set invalidchars to invalidchars & char & space | |
end if | |
end repeat | |
-- we found invalid characters | |
if invalidchars is not "" then | |
set errmsg to "We found the following characters in the given input. Please enter numbers only." & return & return & invalidchars & return | |
my dsperrmsg(errmsg, "--") | |
my getintvalue() | |
else | |
-- let's try to transform the user input into an integer | |
try | |
set intvalue to usrinput as integer | |
return intvalue | |
on error | |
set errmsg to "We could not coerce the given input into an integer:" & return & return & usrinput & return | |
my dsperrmsg(errmsg, "--") | |
my getintvalue() | |
end try | |
end if | |
end if | |
end getintvalue | |
-- I am displaying error messages to the user | |
on dsperrmsg(errmsg, errnum) | |
tell me | |
activate | |
display dialog errmsg & " (" & errnum & ")" buttons {"OK"} default button 1 with title mytitle with icon stop | |
end tell | |
end dsperrmsg | |
-- isNumString :: String -> Bool | |
on isNumString(s) | |
try | |
if class of s is string then | |
set c to class of (s as number) | |
c is real or c is integer | |
else | |
false | |
end if | |
on error | |
false | |
end try | |
end isNumString | |
on getHighlight(debug) | |
--Save the current contents of the clipboard | |
try | |
set theSpare to the clipboard --as text | |
on error | |
set response to (display dialog "Warning: The contents of the clipboard will be lost." buttons {"Cancel", "OK"}) | |
if button returned of response is "OK" then | |
set theSpare to "" | |
end if | |
end try | |
set the clipboard to "" | |
--Declare the variable we're going to return | |
set selecTxt to "" | |
tell application "System Events" | |
--Initiate the copy | |
keystroke "c" using {command down} | |
--Wait up to 2 seconds for the copy to finish | |
set done to "no" | |
set waitnum to 0 | |
set waitInterval to 0.02 | |
set maxwaits to 100 | |
--Repeat while the clipboard contents have not changed | |
repeat while done = "no" | |
--Get the contents of the clipboard | |
try | |
set selecTxt to the clipboard as text | |
end try | |
--See if we're done or need to wait | |
if waitnum is equal to maxwaits then | |
set done to "yes" | |
else if selecTxt is equal to "" then | |
delay waitInterval | |
set waitnum to waitnum + 1 | |
else | |
set done to "yes" | |
end if | |
end repeat | |
if debug is true then | |
try | |
display dialog "Copied text: " & (the clipboard as text) | |
end try | |
end if | |
end tell | |
--Restore the original clipboard contents | |
set the clipboard to theSpare --as record | |
if debug is true then | |
try | |
display dialog "The clipboard contents have been restored to " & (the clipboard as text) | |
end try | |
end if | |
--Return the highlighted text | |
return selecTxt | |
end getHighlight | |
on countSequenceChars(seq) | |
set AppleScript's text item delimiters to {space, tab, linefeed, return} | |
set selText to text items of seq | |
set AppleScript's text item delimiters to {} | |
set selText to selText as string | |
set len to count characters of selText | |
return (len as integer) | |
end countSequenceChars | |
--Uses the down arrow to grab at least n characters of nucleotides and returns the newly selected string and the number of nucleotides it contains | |
on selectAtLeastAln(initial_str as string, n as integer, debug) | |
set cur_str to initial_str | |
set character_count to ((count characters of cur_str) as integer) | |
set last_character_count to 0 | |
set nt_count to ((my countSequenceChars(cur_str)) as integer) | |
repeat while character_count > last_character_count and nt_count < n | |
--Add a line to the selection | |
tell application "System Events" to key code 125 using {shift down} | |
set cur_str to (my getHighlight(debug)) | |
set last_character_count to character_count | |
set character_count to ((count characters of cur_str) as integer) | |
set nt_count to (my countSequenceChars(cur_str)) | |
end repeat | |
if nt_count < n then | |
display dialog "Error: Unable to select enough sequence. Please make sure to select more sequence than the target length (" & (n as string) & ")." | |
return ({"", 0}) | |
end if | |
return ({cur_str as string, nt_count as integer}) | |
end selectAtLeastAln |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment