edit-attention.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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. target.setSelectionRange(selectionStart, selectionEnd);
  54. return true;
  55. }
  56. // If the user hasn't selected anything, let's select their current parenthesis block or word
  57. if (!selectCurrentParenthesisBlock('<', '>') && !selectCurrentParenthesisBlock('(', ')') && !selectCurrentParenthesisBlock('[', ']')) {
  58. selectCurrentWord();
  59. }
  60. event.preventDefault();
  61. var closeCharacter = ')';
  62. var delta = opts.keyedit_precision_attention;
  63. var start = selectionStart > 0 ? text[selectionStart - 1] : "";
  64. var end = text[selectionEnd];
  65. if (start == '<') {
  66. closeCharacter = '>';
  67. delta = opts.keyedit_precision_extra;
  68. } else if (start == '(' && end == ')' || start == '[' && end == ']') { // convert old-style (((emphasis)))
  69. let numParen = 0;
  70. while (text[selectionStart - numParen - 1] == start && text[selectionEnd + numParen] == end) {
  71. numParen++;
  72. }
  73. if (start == "[") {
  74. weight = (1 / 1.1) ** numParen;
  75. } else {
  76. weight = 1.1 ** numParen;
  77. }
  78. weight = Math.round(weight / opts.keyedit_precision_attention) * opts.keyedit_precision_attention;
  79. text = text.slice(0, selectionStart - numParen) + "(" + text.slice(selectionStart, selectionEnd) + ":" + weight + ")" + text.slice(selectionEnd + numParen);
  80. selectionStart -= numParen - 1;
  81. selectionEnd -= numParen - 1;
  82. } else if (start != '(') {
  83. // do not include spaces at the end
  84. while (selectionEnd > selectionStart && text[selectionEnd - 1] == ' ') {
  85. selectionEnd--;
  86. }
  87. if (selectionStart == selectionEnd) {
  88. return;
  89. }
  90. text = text.slice(0, selectionStart) + "(" + text.slice(selectionStart, selectionEnd) + ":1.0)" + text.slice(selectionEnd);
  91. selectionStart++;
  92. selectionEnd++;
  93. }
  94. if (text[selectionEnd] != ':') return;
  95. var weightLength = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;
  96. var weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + weightLength));
  97. if (isNaN(weight)) return;
  98. weight += isPlus ? delta : -delta;
  99. weight = parseFloat(weight.toPrecision(12));
  100. if (Number.isInteger(weight)) weight += ".0";
  101. if (closeCharacter == ')' && weight == 1) {
  102. var endParenPos = text.substring(selectionEnd).indexOf(')');
  103. text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + endParenPos + 1);
  104. selectionStart--;
  105. selectionEnd--;
  106. } else {
  107. text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + weightLength);
  108. }
  109. target.focus();
  110. target.value = text;
  111. target.selectionStart = selectionStart;
  112. target.selectionEnd = selectionEnd;
  113. updateInput(target);
  114. }
  115. addEventListener('keydown', (event) => {
  116. keyupEditAttention(event);
  117. });