From 1cc7c4bfb31b80b6667154145f1455541951db18 Mon Sep 17 00:00:00 2001
From: missionfloyd <missionfloyd@users.noreply.github.com>
Date: Sat, 30 Sep 2023 01:09:09 -0600
Subject: [PATCH 1/4] Allow editing whitespace delimiters

---
 javascript/edit-attention.js | 3 ++-
 modules/shared_options.py    | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js
index 8906c8922..bc4ebed4c 100644
--- a/javascript/edit-attention.js
+++ b/javascript/edit-attention.js
@@ -46,7 +46,8 @@ function keyupEditAttention(event) {
 
     function selectCurrentWord() {
         if (selectionStart !== selectionEnd) return false;
-        const delimiters = opts.keyedit_delimiters + " \r\n\t";
+        let delimiters = opts.keyedit_delimiters.replace(/(^|[^\\])(\\\\)*\\$/, "$&\\").replace(/(^|[^\\])((\\\\)*")/g, "$1\\$2");
+        delimiters = JSON.parse(`"${delimiters}"`);
 
         // seek backward until to find beggining
         while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) {
diff --git a/modules/shared_options.py b/modules/shared_options.py
index 00b273faa..a1f157c66 100644
--- a/modules/shared_options.py
+++ b/modules/shared_options.py
@@ -255,7 +255,7 @@ options_templates.update(options_section(('ui', "User interface"), {
     "dimensions_and_batch_together": OptionInfo(True, "Show Width/Height and Batch sliders in same row").needs_reload_ui(),
     "keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
     "keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing <extra networks:0.9>", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
-    "keyedit_delimiters": OptionInfo(".,\\/!?%^*;:{}=`~()", "Ctrl+up/down word delimiters"),
+    "keyedit_delimiters": OptionInfo(r".,\\/!?%^*;:{}=`~() \r\n\t", "Ctrl+up/down word delimiters"),
     "keyedit_move": OptionInfo(True, "Alt+left/right moves prompt elements"),
     "quicksettings_list": OptionInfo(["sd_model_checkpoint"], "Quicksettings list", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that appear at the top of page rather than in settings tab").needs_reload_ui(),
     "ui_tab_order": OptionInfo([], "UI tab order", ui_components.DropdownMulti, lambda: {"choices": list(shared.tab_names)}).needs_reload_ui(),

From 0935d2c3047210b799cbc6f8ce15d3dffca95af7 Mon Sep 17 00:00:00 2001
From: missionfloyd <missionfloyd@users.noreply.github.com>
Date: Sat, 30 Sep 2023 18:37:44 -0600
Subject: [PATCH 2/4] Use checkboxes for whitespace delimiters

---
 javascript/edit-attention.js | 8 ++++++--
 modules/shared_options.py    | 3 ++-
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js
index bc4ebed4c..943d81b08 100644
--- a/javascript/edit-attention.js
+++ b/javascript/edit-attention.js
@@ -46,8 +46,12 @@ function keyupEditAttention(event) {
 
     function selectCurrentWord() {
         if (selectionStart !== selectionEnd) return false;
-        let delimiters = opts.keyedit_delimiters.replace(/(^|[^\\])(\\\\)*\\$/, "$&\\").replace(/(^|[^\\])((\\\\)*")/g, "$1\\$2");
-        delimiters = JSON.parse(`"${delimiters}"`);
+        const whitespace_delimiters = {"Tab": "\t", "Carriage Return": "\r", "Line Feed": "\n"};
+        let delimiters = opts.keyedit_delimiters;
+
+        for (let i of opts.keyedit_delimiters_whitespace) {
+            delimiters += whitespace_delimiters[i];
+        }
 
         // seek backward until to find beggining
         while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) {
diff --git a/modules/shared_options.py b/modules/shared_options.py
index a1f157c66..717c948b5 100644
--- a/modules/shared_options.py
+++ b/modules/shared_options.py
@@ -255,7 +255,8 @@ options_templates.update(options_section(('ui', "User interface"), {
     "dimensions_and_batch_together": OptionInfo(True, "Show Width/Height and Batch sliders in same row").needs_reload_ui(),
     "keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
     "keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing <extra networks:0.9>", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
-    "keyedit_delimiters": OptionInfo(r".,\\/!?%^*;:{}=`~() \r\n\t", "Ctrl+up/down word delimiters"),
+    "keyedit_delimiters": OptionInfo(r".,\/!?%^*;:{}=`~() ", "Ctrl+up/down word delimiters"),
+    "keyedit_delimiters_whitespace": OptionInfo(["Tab", "Carriage Return", "Line Feed"], "Ctrl+up/down whitespace delimiters", gr.CheckboxGroup, lambda: {"choices": ["Tab", "Carriage Return", "Line Feed"]}),
     "keyedit_move": OptionInfo(True, "Alt+left/right moves prompt elements"),
     "quicksettings_list": OptionInfo(["sd_model_checkpoint"], "Quicksettings list", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that appear at the top of page rather than in settings tab").needs_reload_ui(),
     "ui_tab_order": OptionInfo([], "UI tab order", ui_components.DropdownMulti, lambda: {"choices": list(shared.tab_names)}).needs_reload_ui(),

From 0eb5fde2fd42184f431ccba5f25d714272e3e6b0 Mon Sep 17 00:00:00 2001
From: missionfloyd <missionfloyd@users.noreply.github.com>
Date: Sat, 30 Sep 2023 21:20:58 -0600
Subject: [PATCH 3/4] Remove unneeded code

---
 javascript/edit-attention.js | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js
index 943d81b08..df218c1e4 100644
--- a/javascript/edit-attention.js
+++ b/javascript/edit-attention.js
@@ -18,22 +18,11 @@ function keyupEditAttention(event) {
         const before = text.substring(0, selectionStart);
         let beforeParen = before.lastIndexOf(OPEN);
         if (beforeParen == -1) return false;
-        let beforeParenClose = before.lastIndexOf(CLOSE);
-        while (beforeParenClose !== -1 && beforeParenClose > beforeParen) {
-            beforeParen = before.lastIndexOf(OPEN, beforeParen - 1);
-            beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1);
-        }
 
         // Find closing parenthesis around current cursor
         const after = text.substring(selectionStart);
         let afterParen = after.indexOf(CLOSE);
         if (afterParen == -1) return false;
-        let afterParenOpen = after.indexOf(OPEN);
-        while (afterParenOpen !== -1 && afterParen > afterParenOpen) {
-            afterParen = after.indexOf(CLOSE, afterParen + 1);
-            afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1);
-        }
-        if (beforeParen === -1 || afterParen === -1) return false;
 
         // Set the selection to the text between the parenthesis
         const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen);
@@ -53,7 +42,7 @@ function keyupEditAttention(event) {
             delimiters += whitespace_delimiters[i];
         }
 
-        // seek backward until to find beggining
+        // seek backward to find beginning
         while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) {
             selectionStart--;
         }

From 56ef5e9d48750fd43f9faba31ff67e64368153b7 Mon Sep 17 00:00:00 2001
From: missionfloyd <missionfloyd@users.noreply.github.com>
Date: Sat, 30 Sep 2023 21:44:05 -0600
Subject: [PATCH 4/4] Remove end parenthesis from weight

---
 javascript/edit-attention.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js
index df218c1e4..794453bfe 100644
--- a/javascript/edit-attention.js
+++ b/javascript/edit-attention.js
@@ -86,7 +86,7 @@ function keyupEditAttention(event) {
     }
 
     var end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;
-    var weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end));
+    var weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + end));
     if (isNaN(weight)) return;
 
     weight += isPlus ? delta : -delta;