@@ -208,6 +208,24 @@ function getBlockType() {
208208 return "P" ;
209209}
210210
211+ function _exitBlockBelow ( blockEl , contentEl ) {
212+ let next = blockEl . nextElementSibling ;
213+ if ( ! next || next . tagName === "PRE" || next . classList ?. contains ( "table-wrapper" ) ) {
214+ next = document . createElement ( "p" ) ;
215+ next . innerHTML = "<br>" ;
216+ blockEl . parentNode . insertBefore ( next , blockEl . nextSibling ) ;
217+ }
218+ const range = document . createRange ( ) ;
219+ range . selectNodeContents ( next ) ;
220+ range . collapse ( true ) ;
221+ const sel = window . getSelection ( ) ;
222+ sel . removeAllRanges ( ) ;
223+ sel . addRange ( range ) ;
224+ if ( contentEl ) {
225+ contentEl . dispatchEvent ( new Event ( "input" , { bubbles : true } ) ) ;
226+ }
227+ }
228+
211229function _exitTableBelow ( tableEl , contentEl ) {
212230 const wrapper = tableEl . closest ( ".table-wrapper" ) || tableEl ;
213231 // Use existing next sibling if it's a block element, otherwise create a <p>
@@ -1696,6 +1714,41 @@ function enterEditMode(content) {
16961714 }
16971715 }
16981716
1717+ // ArrowDown at end of code block → exit to paragraph below
1718+ if ( e . key === "ArrowDown" && ! mod ) {
1719+ const sel = window . getSelection ( ) ;
1720+ if ( sel && sel . rangeCount ) {
1721+ let node = sel . anchorNode ;
1722+ if ( node ?. nodeType === Node . TEXT_NODE ) node = node . parentElement ;
1723+ const pre = node ?. closest ( "pre" ) ;
1724+ if ( pre && pre . closest ( "#viewer-content" ) ) {
1725+ const range = sel . getRangeAt ( 0 ) ;
1726+ if ( range . collapsed ) {
1727+ const code = pre . querySelector ( "code" ) || pre ;
1728+ // Check if cursor is on the last line
1729+ const textContent = code . textContent || "" ;
1730+ const lastNewline = textContent . lastIndexOf ( "\n" ) ;
1731+ // Get cursor offset within code
1732+ let cursorOffset = 0 ;
1733+ const tw = document . createTreeWalker ( code , NodeFilter . SHOW_TEXT ) ;
1734+ let n ;
1735+ while ( ( n = tw . nextNode ( ) ) ) {
1736+ if ( n === range . startContainer ) {
1737+ cursorOffset += range . startOffset ;
1738+ break ;
1739+ }
1740+ cursorOffset += n . textContent . length ;
1741+ }
1742+ if ( cursorOffset >= lastNewline ) {
1743+ e . preventDefault ( ) ;
1744+ _exitBlockBelow ( pre , content ) ;
1745+ return ;
1746+ }
1747+ }
1748+ }
1749+ }
1750+ }
1751+
16991752 if ( e . key === " " ) {
17001753 handleMarkdownShortcutOnSpace ( e , content ) ;
17011754 return ;
@@ -1738,6 +1791,39 @@ function enterEditMode(content) {
17381791 }
17391792
17401793 if ( e . key === "Enter" ) {
1794+ // Shift+Enter on last line of code block → exit to paragraph below
1795+ if ( e . shiftKey ) {
1796+ const sel = window . getSelection ( ) ;
1797+ if ( sel && sel . rangeCount ) {
1798+ let node = sel . anchorNode ;
1799+ if ( node ?. nodeType === Node . TEXT_NODE ) node = node . parentElement ;
1800+ const pre = node ?. closest ( "pre" ) ;
1801+ if ( pre && pre . closest ( "#viewer-content" ) ) {
1802+ const code = pre . querySelector ( "code" ) || pre ;
1803+ const range = sel . getRangeAt ( 0 ) ;
1804+ if ( range . collapsed ) {
1805+ const textContent = code . textContent || "" ;
1806+ const lastNewline = textContent . lastIndexOf ( "\n" ) ;
1807+ let cursorOffset = 0 ;
1808+ const tw = document . createTreeWalker ( code , NodeFilter . SHOW_TEXT ) ;
1809+ let n ;
1810+ while ( ( n = tw . nextNode ( ) ) ) {
1811+ if ( n === range . startContainer ) {
1812+ cursorOffset += range . startOffset ;
1813+ break ;
1814+ }
1815+ cursorOffset += n . textContent . length ;
1816+ }
1817+ if ( cursorOffset >= lastNewline ) {
1818+ e . preventDefault ( ) ;
1819+ _exitBlockBelow ( pre , content ) ;
1820+ return ;
1821+ }
1822+ }
1823+ }
1824+ }
1825+ }
1826+
17411827 // Inside table: block Enter except on last cell or outside cells where it exits
17421828 if ( isInsideTableOrWrapper ( ) ) {
17431829 e . preventDefault ( ) ;
0 commit comments