Pick from list - enabling repeat

I have am writing a simple nested ‘choose from list’ system which allows me to select standard text sentences from a list. The selected sentence is copied to the clipboard for pasting into the document that I am working on. All is working ok but I want the ability to go back to the Subject List (subjectLst) from any of the sub lists (doorLst, windowLst etc…). I tried putting the subjectLst in a sub routine and calling it if the “Return to subject list…” item is selected but I couldn’t get that to work.
In the working version, there are 20 odd lists with several items in each.

Any guidance welcome. Thanks.

set subjectLst to {"Doors", "Windows", "Electric cupboards"}

set doorLst to {"Return to subject list...", "Door 1", "Door 2"}

set windowLst to {"Window 1", "Window 2"}

set electricCupboardLst to {"Electrical 1", "Electrical 2"}


set subjectAnswer to choose from list subjectLst with prompt "Choose subject matter..." with title "Choose subject matter..."
if subjectAnswer is not false then
	repeat with subjectItem in subjectAnswer
		set theRequest to subjectItem as text
		
		if theRequest = "Doors" then
			set doorAnswer to choose from list doorLst with prompt "Choose comment..." with title "Doors..."
			if doorAnswer is not false then
				set the clipboard to item 1 of doorAnswer
			end if
		end if
		
		if theRequest = "Windows" then
			set windowAnswer to choose from list windowLst with prompt "Choose comment..." with title "Windows..."
			if windowAnswer is not false then
				set the clipboard to item 1 of windowAnswer
			end if
		end if
		
		if theRequest = "Electric cupboards" then
			set electricCupboardAnswer to choose from list electricCupboardLst with prompt "Choose comment..." with title "Electric Cupboards..."
			if electricCupboardAnswer is not false then
				set the clipboard to item 1 of electricCupboardAnswer
			end if
		end if
	end repeat
end if

try this…


set flag to true
set {tid, text item delimiters} to {text item delimiters, return}

repeat while flag
	set subjectList to {"Doors", "Windows", "Electric cupboards"}
	set subjectAnswer to choose from list subjectList with prompt "Choose subject matter..." with title "Choose subject matter..."
	if subjectAnswer is false then
		set flag to false
	else
		set subjectItem to item 1 of subjectAnswer
		set tmp to subjectList as text
		set c to count of paragraphs of (text 1 thru (offset of subjectItem in tmp) of tmp)
		set {requestTitle, subjectList} to item c of {{"Doors…", {"Door 1", "Door 2"}}, {"Windows", {"Window 1", "Window 2"}}, {"Electric Cupboards…", {"Electrical 1", "Electrical 2"}}}
		set subjectAnswer to choose from list subjectList with prompt "Choose comment..." with title requestTitle
		if subjectAnswer is not false then
			set the clipboard to item 1 of subjectAnswer
			set flag to false
		end if
	end if
end repeat
set text item delimiters to tid

Niscors. The following addresses this issue. It’s not clear to me how you are going to associate the response from the second dialog (for example “Door 2”) with a sentence, but I’m sure you have that figured out. I simplified the script a bit just for testing.

setClipboard()
the clipboard -- just for testing

on setClipboard()
	set subjectLst to {"Doors", "Windows"}
	set doorLst to {"Try again", "Door 1", "Door 2"}
	set windowLst to {"Try again", "Window 1", "Window 2"}
	repeat
		set subjectAnswer to choose from list subjectLst with prompt "Choose subject matter..." with title "Choose subject matter..."
		if subjectAnswer is false then error number -128
		if subjectAnswer = {"Doors"} then
			set doorAnswer to choose from list doorLst with prompt "Choose comment..." with title "Doors..."
			if doorAnswer is false then error number -128
			if doorAnswer is not {"Try again"} then
				set the clipboard to item 1 of doorAnswer
				return
			end if
		else if subjectAnswer = {"Windows"} then
			set windowAnswer to choose from list windowLst with prompt "Choose comment..." with title "Windows..."
			if windowAnswer is false then error number -128
			if windowAnswer is not {"Try again"} then
				set the clipboard to item 1 of windowAnswer
				return
			end if
		end if
	end repeat
end setClipboard

I think “choose from list” is not a good interface. My “choose multiple list” Script Library gives you a multiple popup menu dialog easy to use with AppleScript.

スクリーンショット 2023-12-30 17.18.13

http://piyocast.com/as/asinyaye

--
--	Created by: Takaaki Naganoya
--	Created on: 2023/12/30
--
--	Copyright © 2023 Piyomaru Software, All Rights Reserved
--
use AppleScript version "2.7" -- High Sierra (10.13) or later
use framework "Foundation"
use scripting additions
use mulList : script "choose multiple list"

set selList to {{"Door 1", "Door 2"}, {"Window 1", "Window 2"}, {"Electrical 1", "Electrical 2"}}
set tList to {"Doors", "Windows", "Electric cupboards"}

set aRes to choose multiple list selList main message "Select Items Demo" sub message "Select each selection." with title lists tList height 200 width 400 return type item contents with allow same items
--> {"Door 1", "Window 1", "Electrical 1"}

Fredrik71’s suggestion is excellent, and all it needs is the try-again option and some error correction:

use framework "Foundation"
use scripting additions

setClipboard()
the clipboard -- just for testing

on setClipboard()
	set subjectLst to {"Doors", "Windows", "Electric Cupboard"} -- user set values this section
	set doorLst to {"Door 1", "Door 2"}
	set windowLst to {"Window 1", "Window 2"}
	set electricCupboardLst to {"Electrical 1", "Electrical 2"}
	set sentenceLists to {doorLst, windowLst, electricCupboardLst}
	
	set subjectArray to current application's NSArray's arrayWithArray:subjectLst
	set sentenceArray to current application's NSArray's arrayWithArray:sentenceLists
	set theDictionary to current application's NSDictionary's dictionaryWithObjects:sentenceArray forKeys:subjectArray
	
	repeat
		set theSubject to (choose from list subjectLst)
		if theSubject is false then error number -128
		set theSubject to item 1 of theSubject
		set dialogList to ((theDictionary's valueForKey:theSubject) as list) & "Try Again"
		set theSentence to (choose from list dialogList)
		if theSentence is false then error number -128
		set theSentence to item 1 of theSentence
		if theSentence is not "Try Again" then
			set the clipboard to theSentence
			return
		end if
	end repeat
end setClipboard

Many thanks for all of these responses. I’ve gone with peavine’s solution because it keeps the lists separate which will make it much easier for me to make any changes that may be required to the standard text sentences (‘Door 1’ for example is actually a 15 word sentence which is hard coded as item 2 of doorLst).
Ta

If the main reason you didn’t like mine is because you wanted each list separate for editing, here is mine modified like peavines. I liked his use of only one repeat loop.

use scripting additions

setClipboard()
the clipboard -- just for testing

on setClipboard()
	local subjectLst, theRecord, theSubject, dialogList, theSentence
	set {tid, text item delimiters} to {text item delimiters, return}
	set subjectLst to {"Doors", "Windows", "Electric Cupboard"}
	set doorLst to {"Door 1", "Door 2"}
	set windowLst to {"Window 1", "Window 2"}
	set electricCupboardLst to {"Electrical 1", "Electrical 2"}
	set tmp to subjectLst as text
	repeat
		set theSubject to choose from list subjectLst with prompt "Choose subject matter..." with title "Choose subject matter..."
		if theSubject is false then error number -128
		set theSubject to item 1 of theSubject
		set c to count of paragraphs of (text 1 thru (offset of theSubject in tmp) of tmp)
		set {requestTitle, dialogList} to item c of {{"a Door", doorLst}, {"a Window", windowLst}, {"an Electric Cupboard", electricCupboardLst}}
		set theSentence to choose from list (dialogList & "Try Again") with prompt ("Choose " & requestTitle & " from below…") with title ("Choose " & requestTitle)
		if theSentence is false then error number -128
		set theSentence to item 1 of theSentence
		if theSentence is not "Try Again" then
			set the clipboard to theSentence
			exit repeat
		end if
	end repeat
	set text item delimiters to tid
end setClipboard

Also, I’m of the mind to not use AppleScriptObjC for things that can be done natively in regular AppleScript, when doing so does not have a major speed benefit. Because loading the frameworks has an overhead issue, both in time and memory. In this case it is also a tiny bit slower.

I liked them all :+1:.
Thanks for helping me out.

How come you dont apply the same discretion to the use of do shell script ?

But I do.

“do shell script” doesn’t have nearly as much overhead as ApplescriptObjC, but it still has speed overhead on initial loading. But most times I use it to get to functions that are not available in AppleScript.

Here’s a version using Dialog Toolkit Plus, which gives you popups, rather than choose from list. It stays open until you hit cancel. It also remembers your previous selection.

(Of course you’d need to replace the default lists with your own)

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use script "Dialog Toolkit Plus"
property startingDate : (current date)

set subjectList to {"Doors", "Windows", "Floors", "Ceilings", "Walls", "Light Fixtures", "Plumbing Fixtures", "Appliances", "Furniture", "Media", "Built Ins", "Cabinets", "Garages", "Porches", "Roofs", "Foundations"}
set subLists to {}
set the end of subLists to {"", "Doors1", "Doors2", "Doors3", "Doors4", "Doors5", "Doors6", "Doors7", "Doors8", "Doors9", "Doors10"}
set the end of subLists to {"", "Windows1", "Windows2", "Windows3", "Windows4", "Windows5", "Windows6", "Windows7", "Windows8", "Windows9", "Windows10"}
set the end of subLists to {"", "Floors1", "Floors2", "Floors3", "Floors4", "Floors5", "Floors6", "Floors7", "Floors8", "Floors9", "Floors10"}
set the end of subLists to {"", "Ceilings1", "Ceilings2", "Ceilings3", "Ceilings4", "Ceilings5", "Ceilings6", "Ceilings7", "Ceilings8", "Ceilings9", "Ceilings10"}
set the end of subLists to {"", "Walls1", "Walls2", "Walls3", "Walls4", "Walls5", "Walls6", "Walls7", "Walls8", "Walls9", "Walls10"}
set the end of subLists to {"", "Light Fixtures1", "Light Fixtures2", "Light Fixtures3", "Light Fixtures4", "Light Fixtures5", "Light Fixtures6", "Light Fixtures7", "Light Fixtures8", "Light Fixtures9", "Light Fixtures10"}
set the end of subLists to {"", "Plumbing Fixtures1", "Plumbing Fixtures2", "Plumbing Fixtures3", "Plumbing Fixtures4", "Plumbing Fixtures5", "Plumbing Fixtures6", "Plumbing Fixtures7", "Plumbing Fixtures8", "Plumbing Fixtures9", "Plumbing Fixtures10"}
set the end of subLists to {"", "Appliances1", "Appliances2", "Appliances3", "Appliances4", "Appliances5", "Appliances6", "Appliances7", "Appliances8", "Appliances9", "Appliances10"}
set the end of subLists to {"", "Furniture1", "Furniture2", "Furniture3", "Furniture4", "Furniture5", "Furniture6", "Furniture7", "Furniture8", "Furniture9", "Furniture10"}
set the end of subLists to {"", "Media1", "Media2", "Media3", "Media4", "Media5", "Media6", "Media7", "Media8", "Media9", "Media10"}
set the end of subLists to {"", "Built Ins1", "Built Ins2", "Built Ins3", "Built Ins4", "Built Ins5", "Built Ins6", "Built Ins7", "Built Ins8", "Built Ins9", "Built Ins10"}
set the end of subLists to {"", "Cabinets1", "Cabinets2", "Cabinets3", "Cabinets4", "Cabinets5", "Cabinets6", "Cabinets7", "Cabinets8", "Cabinets9", "Cabinets10"}
set the end of subLists to {"", "Garages1", "Garages2", "Garages3", "Garages4", "Garages5", "Garages6", "Garages7", "Garages8", "Garages9", "Garages10"}
set the end of subLists to {"", "Porches1", "Porches2", "Porches3", "Porches4", "Porches5", "Porches6", "Porches7", "Porches8", "Porches9", "Porches10"}
set the end of subLists to {"", "Roofs1", "Roofs2", "Roofs3", "Roofs4", "Roofs5", "Roofs6", "Roofs7", "Roofs8", "Roofs9", "Roofs10"}
set the end of subLists to {"", "Foundations1", "Foundations2", "Foundations3", "Foundations4", "Foundations5", "Foundations6", "Foundations7", "Foundations8", "Foundations9", "Foundations10"}

set AppleScript's text item delimiters to {return}

set accViewControls to {}
set controlResults to {}
set accViewWidth to 350
set theBottom to 0
set spacer to 4
set theTop to spacer

--Variables
set buttonList to {("Cancel"), ("Okay"), ("Copy")}

set windowTitle to "Window title"
set initialPosition to {30, 30}

--Build window buttons

set {theButtons, theWidth} to create buttons buttonList ¬
   default button 3 ¬
   cancel button 1 ¬
   equal widths false ¬
   --button keys {textList}

if theWidth > accViewWidth then set accViewWidth to theWidth

-->ACC views go here
-->>Labeled popups
repeat with x from 1 to count of subjectList
   set thisSubject to item x of subjectList
   set subjectSublist to item x of subLists
   set theBottom to (theTop + spacer)
   
   set popupLeft to max width for labels {thisSubject} ¬
      control size regular size ¬
      without bold type
   set popupLeft to popupLeft + spacer
   
   set popupOptions to subjectSublist
   
   set popupWidth to max width for labels popupOptions ¬
      control size large size ¬
      with bold type
   
   set {theLabeledPopup, thePopUpLabel, theTop} to create labeled popup popupOptions ¬
      left inset spacer ¬
      bottom theBottom ¬
      popup width popupWidth + 30 ¬
      initial choice 1 ¬
      max width accViewWidth ¬
      label text thisSubject ¬
      popup left popupLeft
   set the beginning of accViewControls to theLabeledPopup
   set the end of accViewControls to thePopUpLabel
   --<<Labeled popup
end repeat

--<<end ACC views
repeat
   --Display Extended window
   set accViewHeight to theTop
   set clipboardString to ""
   set {buttonClicked, controlValues} to ¬
      display enhanced window windowTitle ¬
         buttons theButtons ¬
         acc view width accViewWidth ¬
         acc view height accViewHeight ¬
         acc view controls accViewControls ¬
         initial position initialPosition ¬
         with align cancel button
   --giving up after 60
   set itemSelected to false
   
   repeat with x from 1 to count of popupOptions
      if item x of controlValues is not in {"missing value", missing value} then
         set itemSelected to true
         set the clipboardString to (clipboardString & item x of controlValues as text) & return & return
      end if
   end repeat
   
   if buttonClicked is "Copy" and itemSelected then
      set the clipboard to clipboardString
   else
      if buttonClicked is "Cancel" then exit repeat
   end if
end repeat
return clipboardString