edit-attention.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. function keyupEditAttention(event) {
  2. let target = event.originalTarget || event.composedPath()[0];
  3. if (!target.matches("*:is([id*='_toprow'] [id*='_prompt'], .prompt) textarea")) return;
  4. if (!(event.metaKey || event.ctrlKey)) return;
  5. let isPlus = event.key == "ArrowUp";
  6. let isMinus = event.key == "ArrowDown";
  7. if (!isPlus && !isMinus) return;
  8. let selectionStart = target.selectionStart;
  9. let selectionEnd = target.selectionEnd;
  10. let text = target.value;
  11. function selectCurrentParenthesisBlock(OPEN, CLOSE) {
  12. if (selectionStart !== selectionEnd) return false;
  13. // Find opening parenthesis around current cursor
  14. const before = text.substring(0, selectionStart);
  15. let beforeParen = before.lastIndexOf(OPEN);
  16. if (beforeParen == -1) return false;
  17. let beforeClosingParen = before.lastIndexOf(CLOSE);
  18. if (beforeClosingParen != -1 && beforeClosingParen > beforeParen) return false;
  19. // Find closing parenthesis around current cursor
  20. const after = text.substring(selectionStart);
  21. let afterParen = after.indexOf(CLOSE);
  22. if (afterParen == -1) return false;
  23. let afterOpeningParen = after.indexOf(OPEN);
  24. if (afterOpeningParen != -1 && afterOpeningParen < afterParen) return false;
  25. // Set the selection to the text between the parenthesis
  26. const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen);
  27. if (/.*:-?[\d.]+/s.test(parenContent)) {
  28. const lastColon = parenContent.lastIndexOf(":");
  29. selectionStart = beforeParen + 1;
  30. selectionEnd = selectionStart + lastColon;
  31. } else {
  32. selectionStart = beforeParen + 1;
  33. selectionEnd = selectionStart + parenContent.length;
  34. }
  35. target.setSelectionRange(selectionStart, selectionEnd);
  36. return true;
  37. }
  38. function selectCurrentWord() {
  39. if (selectionStart !== selectionEnd) return false;
  40. const whitespace_delimiters = {"Tab": "\t", "Carriage Return": "\r", "Line Feed": "\n"};
  41. let delimiters = opts.keyedit_delimiters;
  42. for (let i of opts.keyedit_delimiters_whitespace) {
  43. delimiters += whitespace_delimiters[i];
  44. }
  45. // seek backward to find beginning
  46. while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) {
  47. selectionStart--;
  48. }
  49. // seek forward to find end
  50. while (!delimiters.includes(text[selectionEnd]) && selectionEnd < text.length) {
  51. selectionEnd++;
  52. }
  53. // deselect surrounding whitespace
  54. while (text[selectionStart] == " " && selectionStart < selectionEnd) {
  55. selectionStart++;
  56. }
  57. while (text[selectionEnd - 1] == " " && selectionEnd > selectionStart) {
  58. selectionEnd--;
  59. }
  60. target.setSelectionRange(selectionStart, selectionEnd);
  61. return true;
  62. }
  63. // If the user hasn't selected anything, let's select their current parenthesis block or word
  64. if (!selectCurrentParenthesisBlock('<', '>') && !selectCurrentParenthesisBlock('(', ')') && !selectCurrentParenthesisBlock('[', ']')) {
  65. selectCurrentWord();
  66. }
  67. event.preventDefault();
  68. var closeCharacter = ')';
  69. var delta = opts.keyedit_precision_attention;
  70. var start = selectionStart > 0 ? text[selectionStart - 1] : "";
  71. var end = text[selectionEnd];
  72. if (start == '<') {
  73. closeCharacter = '>';
  74. delta = opts.keyedit_precision_extra;
  75. } else if (start == '(' && end == ')' || start == '[' && end == ']') { // convert old-style (((emphasis)))
  76. let numParen = 0;
  77. while (text[selectionStart - numParen - 1] == start && text[selectionEnd + numParen] == end) {
  78. numParen++;
  79. }
  80. if (start == "[") {
  81. weight = (1 / 1.1) ** numParen;
  82. } else {
  83. weight = 1.1 ** numParen;
  84. }
  85. weight = Math.round(weight / opts.keyedit_precision_attention) * opts.keyedit_precision_attention;
  86. text = text.slice(0, selectionStart - numParen) + "(" + text.slice(selectionStart, selectionEnd) + ":" + weight + ")" + text.slice(selectionEnd + numParen);
  87. selectionStart -= numParen - 1;
  88. selectionEnd -= numParen - 1;
  89. } else if (start != '(') {
  90. // do not include spaces at the end
  91. while (selectionEnd > selectionStart && text[selectionEnd - 1] == ' ') {
  92. selectionEnd--;
  93. }
  94. if (selectionStart == selectionEnd) {
  95. return;
  96. }
  97. text = text.slice(0, selectionStart) + "(" + text.slice(selectionStart, selectionEnd) + ":1.0)" + text.slice(selectionEnd);
  98. selectionStart++;
  99. selectionEnd++;
  100. }
  101. if (text[selectionEnd] != ':') return;
  102. var weightLength = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;
  103. var weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + weightLength));
  104. if (isNaN(weight)) return;
  105. weight += isPlus ? delta : -delta;
  106. weight = parseFloat(weight.toPrecision(12));
  107. if (Number.isInteger(weight)) weight += ".0";
  108. if (closeCharacter == ')' && weight == 1) {
  109. var endParenPos = text.substring(selectionEnd).indexOf(')');
  110. text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + endParenPos + 1);
  111. selectionStart--;
  112. selectionEnd--;
  113. } else {
  114. text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + weightLength);
  115. }
  116. target.focus();
  117. target.value = text;
  118. target.selectionStart = selectionStart;
  119. target.selectionEnd = selectionEnd;
  120. updateInput(target);
  121. }
  122. addEventListener('keydown', (event) => {
  123. keyupEditAttention(event);
  124. });