MarkdownTableUtil.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import MarkdownTable from '~/client/models/MarkdownTable';
  2. /**
  3. * Utility for markdown table
  4. */
  5. // https://regex101.com/r/7BN2fR/10
  6. const linePartOfTableRE = /^([^\r\n|]*)\|(([^\r\n|]*\|)+)$/;
  7. // https://regex101.com/r/1UuWBJ/3
  8. export const emptyLineOfTableRE = /^([^\r\n|]*)\|((\s*\|)+)$/;
  9. const curPos = (editor) => {
  10. return editor.state.selection.main.head;
  11. };
  12. /**
  13. * return boolean value whether the cursor position is in a table
  14. */
  15. export const isInTable = (editor) => {
  16. const lineText = editor.state.doc.lineAt(curPos(editor)).text;
  17. return linePartOfTableRE.test(lineText);
  18. };
  19. /**
  20. * return the postion of the BOT(beginning of table)
  21. * (If the cursor is not in a table, return its position)
  22. */
  23. export const getBot = (editor) => {
  24. if (!this.isInTable(editor)) {
  25. return curPos(editor);
  26. }
  27. const doc = editor.state.doc;
  28. const firstLine = doc.line(1);
  29. let line = doc.lineAt(curPos(editor)).number - 1;
  30. for (; line >= firstLine.number; line--) {
  31. const strLine = doc.line(line);
  32. if (!linePartOfTableRE.test(strLine.text)) {
  33. break;
  34. }
  35. }
  36. const botLine = doc.line(line + 1);
  37. return botLine.from;
  38. };
  39. /**
  40. * return the postion of the EOT(end of table)
  41. * (If the cursor is not in a table, return its position)
  42. */
  43. export const getEot = (editor) => {
  44. if (!isInTable(editor)) {
  45. return curPos(editor);
  46. }
  47. const doc = editor.state.doc;
  48. const lastLine = doc.line(doc.lines);
  49. let line = doc.lineAt(curPos(editor)).number + 1;
  50. for (; line <= lastLine.number; line++) {
  51. const strLine = doc.line(line);
  52. if (!linePartOfTableRE.test(strLine.text)) {
  53. break;
  54. }
  55. }
  56. const eotLine = doc.line(line - 1);
  57. return eotLine.to;
  58. };
  59. /**
  60. * return strings from BOT(beginning of table) to the cursor position
  61. */
  62. export const getStrFromBot = (editor) => {
  63. return editor.state.sliceDoc(getBot(editor), curPos(editor));
  64. };
  65. /**
  66. * return strings from the cursor position to EOT(end of table)
  67. */
  68. export const getStrToEot = (editor) => {
  69. return editor.state.sliceDoc(curPos(editor), getEot(editor));
  70. };
  71. /**
  72. * return MarkdownTable instance of the table where the cursor is
  73. * (If the cursor is not in a table, return null)
  74. */
  75. export const getMarkdownTable = (editor) => {
  76. if (!isInTable(editor)) {
  77. return;
  78. }
  79. const strFromBotToEot = editor.state.sliceDoc(getBot(editor), getEot(editor));
  80. return MarkdownTable.fromMarkdownString(strFromBotToEot);
  81. };
  82. export const getMarkdownTableFromLine = (markdown, bol, eol) => {
  83. const tableLines = markdown.split(/\r\n|\r|\n/).slice(bol - 1, eol).join('\n');
  84. return MarkdownTable.fromMarkdownString(tableLines);
  85. };
  86. /**
  87. * return boolean value whether the cursor position is end of line
  88. */
  89. export const isEndOfLine = (editor) => {
  90. return (curPos(editor) === editor.state.doc.line(curPos(editor).line + 1).length);
  91. };
  92. /**
  93. * add a row at the end
  94. * (This function overwrite directory markdown table specified as argument.)
  95. * @param {MarkdownTable} markdown table
  96. */
  97. export const addRowToMarkdownTable = (mdtable) => {
  98. const numCol = mdtable.table.length > 0 ? mdtable.table[0].length : 1;
  99. const newRow = [];
  100. (new Array(numCol)).forEach(() => { return newRow.push('') }); // create cols
  101. mdtable.table.push(newRow);
  102. };
  103. /**
  104. * return markdown table that is merged all of markdown table in array
  105. * (The merged markdown table options are used for the first markdown table.)
  106. * @param {Array} array of markdown table
  107. */
  108. export const mergeMarkdownTable = (mdtableList) => {
  109. if (mdtableList == null || !(mdtableList instanceof Array)) {
  110. return undefined;
  111. }
  112. let newTable = [];
  113. const options = mdtableList[0].options; // use option of first markdown-table
  114. mdtableList.forEach((mdtable) => {
  115. newTable = newTable.concat(mdtable.table);
  116. });
  117. return (new MarkdownTable(newTable, options));
  118. };
  119. /**
  120. * replace focused markdown table with editor
  121. * (A replaced table is reformed by markdown-table.)
  122. * @param {MarkdownTable} table
  123. */
  124. export const replaceFocusedMarkdownTableWithEditor = (editor, table) => {
  125. const botPos = getBot(editor);
  126. const eotPos = getEot(editor);
  127. editor.dispatch({
  128. changes: {
  129. from: botPos,
  130. to: eotPos,
  131. insert: table.toString(),
  132. },
  133. });
  134. editor.dispatch({
  135. selection: { anchor: editor.state.doc.lineAt(curPos(editor)).to },
  136. });
  137. };
  138. /**
  139. * return markdown where the markdown table specified by line number params is replaced to the markdown table specified by table param
  140. * @param {string} markdown
  141. * @param {MarkdownTable} table
  142. * @param beginLineNumber
  143. * @param endLineNumber
  144. */
  145. export const replaceMarkdownTableInMarkdown = (table, markdown, beginLineNumber, endLineNumber) => {
  146. const splitMarkdown = markdown.split(/\r\n|\r|\n/);
  147. const markdownBeforeTable = splitMarkdown.slice(0, beginLineNumber - 1);
  148. const markdownAfterTable = splitMarkdown.slice(endLineNumber);
  149. let newMarkdown = '';
  150. if (markdownBeforeTable.length > 0) {
  151. newMarkdown += `${markdownBeforeTable.join('\n')}\n`;
  152. }
  153. newMarkdown += table;
  154. if (markdownAfterTable.length > 0) {
  155. newMarkdown += `\n${markdownAfterTable.join('\n')}`;
  156. }
  157. return newMarkdown;
  158. };