Author Topic: qXed: linked list text editor  (Read 14641 times)

0 Members and 1 Guest are viewing this topic.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: qXed: linked list text editor
« Reply #30 on: September 29, 2018, 06:10:21 pm »
Aright screw it I'll make that change of behavior the next thing I do.
Damn you Pete in the most respectful way possible!
You're not done when it works, you're done when it's right.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: qXed: linked list text editor
« Reply #31 on: September 29, 2018, 06:23:00 pm »
Well, the ESC key just reverses the backspace quirk with an insert quirk. Also, trying that a couple of times made the system lock up.

Anyway, is it my understanding you are also making this as a library for others to use? If so, reinventions are usually expected to follow established norms first, and then add new features. People who are used to the way most WP programs work get a little bent out of shape when they look at what they thought they typed, but the screen results show something different. Especially people like me, who have to look at porn... I mean the keyboard, while I'm typing.

Pete :D
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: qXed: linked list text editor
« Reply #32 on: September 29, 2018, 06:40:18 pm »
Lemme take a quick guess - you don't use VI(m) do you? Want to see a learning curve in a text editor that you will curse up and down and then curse again left and right because somehow its the most pervasive in the world? Pop open a linux terminal, type "vi", and try to get *anything* done. It's almost uncrackable, but somehow the most argued-for text editor ever. Just weird.

Anyway, I'll be updating the top post in a number of minutes. The cursor will do the more natural thing.

Thanks again, these posts become very motivational on my end...
« Last Edit: September 29, 2018, 06:43:01 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: qXed: linked list text editor
« Reply #33 on: September 29, 2018, 06:59:38 pm »
Yeah, I'm nothing if not helpful... HEY, where'd I go!

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: qXed: linked list text editor
« Reply #34 on: September 30, 2018, 09:24:57 am »
Okay, I couldn't resist having a little fun with this one.

I've taken the liberty of pressing the Insert key *for* you in case you want to edit this thing as it goes.

Otherwise, press and hold F7 to watch the Gosper Glider Gun a la Conway's Game of Life.

Code: QB64: [Select]
  1. _TITLE "qXed"
  2. _DELAY .15
  3. SCREEN _NEWIMAGE(90, 30, 0)
  4.  
  5. ' Define fundamental structures.
  6. TYPE Vector
  7.     X AS INTEGER
  8.     Y AS INTEGER
  9.  
  10. TYPE Cell
  11.     Identity AS LONG
  12.     Pointer AS LONG
  13.     Lagger AS LONG
  14.     Content AS STRING * 1
  15.  
  16. DIM SHARED MemLimit AS LONG
  17. DIM SHARED BOC AS LONG ' Beginning of chain.
  18. DIM SHARED EOC AS LONG ' End of chain.
  19. MemLimit = 64000
  20. BOC = -1
  21. EOC = MemLimit
  22.  
  23. ' Define text window properties.
  24. DIM SHARED TextWrapping
  25. DIM SHARED TextFormatting
  26. DIM SHARED VisibleLines
  27. DIM SHARED TopIndent
  28. DIM SHARED LeftIndent
  29. DIM SHARED TextHeight
  30. DIM SHARED TextWidth
  31. DIM SHARED HScroll
  32. DIM SHARED InsertKey
  33. TextWrapping = 1
  34. TextFormatting = -1
  35. TopIndent = 1
  36. LeftIndent = 1
  37. TextHeight = _HEIGHT - 2 * TopIndent
  38. TextWidth = _WIDTH - 2 * LeftIndent
  39. HScroll = 1
  40. InsertKey = 1
  41.  
  42. ' Initiate text inside window.
  43. DIM SHARED StartIndex ' First visible character address.
  44. DIM SHARED LineAsMapped(TextHeight) AS STRING
  45. DIM SHARED Cursor1 AS Vector
  46. DIM SHARED Cursor2 AS Vector
  47.  
  48. DIM SHARED FunGrid(TextWidth, TextHeight, 2) AS STRING
  49.  
  50. ' Load text file into memory if applicable, use example string if not.
  51. DIM SHARED FileName$
  52. IF (c$ <> "") THEN
  53.     q$ = ""
  54.     OPEN c$ FOR INPUT AS #1
  55.     DO WHILE NOT EOF(1)
  56.         LINE INPUT #1, r$
  57.         q$ = q$ + r$ + CHR$(13)
  58.     LOOP
  59.     CLOSE #1
  60.     i = INSTR(c$, ".")
  61.     IF (i <> 0) THEN j = i - 1 ELSE j = LEN(c$)
  62.     FileName$ = LEFT$(c$, j) + "-" + LTRIM$(RTRIM$(STR$(INT(TIMER)))) + ".txt"
  63.     FileName$ = "Newfile" + "-" + DATE$ + "-" + LTRIM$(RTRIM$(STR$(INT(TIMER)))) + ".txt"
  64.     'q$ = "I sank to the floor. I [experienced] this hallucination of tumbling forward into these fractal geometric spaces made of light and then I found myself in the equivalent of the Pope's private chapel and there were insect elf machines proffering strange little tablets with strange writing on them, and I was aghast, completely appalled, because [in] a matter of seconds . . . my entire expectation of the nature of the world was just being shredded in front of me. I've never actually gotten over it. These self-transforming machine elf creatures were speaking in a colored language which condensed into rotating machines that were like Faberge eggs but crafted out of luminescent superconducting ceramics and liquid crystal gels. All this stuff was just so weird and so alien and so un-English-able that it was a complete shock - I mean, the literal turning inside out of [my] intellectual universe!" + CHR$(13) + CHR$(13) + "This went on for two or three minutes, this situation of [discontinuous] orthogonal dimensions to reality just engulfing me. As I came out of it and the room reassembled itself, I said, " + CHR$(34) + "I can't believe it, it's impossible." + CHR$(34) + " To call that a drug is ridiculous; that just means that you just don't have a word for it and so you putter around and you come upon this sloppy concept [that] something goes into your body and there's a change. It's not like that; it's like being struck by noetic lightning. [Note: " + CHR$(34) + "Noetic" + CHR$(34) + " derives from the theologian Pierre Teilhard de Chardin's " + CHR$(34) + "noosphere" + CHR$(34) + " - the collective consciousness of humankind conceived of as a sort of philosophical virtuality.]" + CHR$(13) + CHR$(13) + "[What] astonished me was [that] . . . in the carpets of Central Asia, in the myths of the Maya, in the visions of an Arcimboldi or a Fra Angelico or a Bosch, there is not a hint, not a clue, not an atom of the presence of this thing, This was more [multiplex] than the universe that we share with each other. It was the victory of Neo-Platonic metaphysics; everything [was] made out of a fourth-dimensional mosaic of energy. I was knocked off my feet, and set myself the goal of understanding this. There was really no choice, you see."
  65.     q$ = "                                          " + CHR$(13) + "                                          " + CHR$(13) + "                                          " + CHR$(13) + "                                          " + CHR$(13) + "                         **         **    " + CHR$(13) + "                        * *         **    " + CHR$(13) + "  **       **           **                " + CHR$(13) + "  **      * *                             " + CHR$(13) + "          **      **                      " + CHR$(13) + "                  * *                     " + CHR$(13) + "                  *                       " + CHR$(13) + "                                     **   " + CHR$(13) + "                                     * *  " + CHR$(13) + "                                     *    " + CHR$(13) + "                                          " + CHR$(13) + "                                          " + CHR$(13) + "                          ***             " + CHR$(13) + "                          *               " + CHR$(13) + "                           *              " + CHR$(13) + "                                          " + CHR$(13) + "                                          " + CHR$(13) + "                                          " + CHR$(13)
  66.  
  67. ' Create memory space for string.
  68. DIM SHARED TheChain(MemLimit) AS Cell
  69.  
  70. ' Create character list.
  71. CALL Assimilate(q$)
  72.  
  73. ' Prime main loop.
  74. CALL MapText
  75. CALL CalibrateCursor(ID1)
  76. CALL CalibrateCursor(ID2)
  77. CALL PrintEverything
  78.  
  79. DIM SHARED DEBUG$
  80.  
  81. DO ' Main loop.
  82.     IF StateChange THEN PrintEverything
  83.     _DISPLAY
  84.     _LIMIT 120
  85.  
  86. SUB PrintEverything
  87.     CLS
  88.     COLOR 7, 1
  89.     FOR i = 1 TO VisibleLines
  90.         c$ = LineAsMapped(i)
  91.         IF ((TextFormatting = 1) AND (TextWrapping <> 2)) THEN
  92.             FOR j = 1 TO TextWidth - LEN(c$)
  93.                 c$ = c$ + "_"
  94.             NEXT
  95.         END IF
  96.         _PRINTSTRING (LeftIndent + 1, TopIndent + i), MID$(c$, HScroll, TextWidth)
  97.     NEXT
  98.  
  99.     COLOR 11, 0
  100.     c$ = "qXed" + DEBUG$
  101.     _PRINTSTRING (1, 1), c$
  102.  
  103.     IF ((Cursor2.X > 0 AND Cursor2.X < _WIDTH) AND ((Cursor2.Y > 0) AND (Cursor2.Y < _HEIGHT))) THEN
  104.         p1 = LinearCount(StartIndex, ID1)
  105.         p2 = LinearCount(StartIndex, ID2)
  106.         pe = LinearCount(StartIndex, EOC)
  107.         IF ((p2 > p1) AND (p2 < pe)) THEN
  108.             COLOR 0, 6
  109.             c$ = TheChain(ID2).Content
  110.             IF (c$ = " ") THEN c$ = "_"
  111.             IF (c$ = CHR$(13)) THEN c$ = "~"
  112.             _PRINTSTRING (Cursor2.X, Cursor2.Y), c$
  113.         END IF
  114.     END IF
  115.  
  116.     IF ((Cursor1.X > 0 AND Cursor1.X < _WIDTH) AND ((Cursor1.Y > 0) AND (Cursor1.Y < _HEIGHT))) THEN
  117.         IF ((Cursor1.X = Cursor2.X) AND (Cursor1.Y = Cursor2.Y)) THEN COLOR 16, 5 ELSE COLOR 16, 3
  118.         c$ = TheChain(ID1).Content
  119.         IF (c$ = " ") THEN c$ = "_"
  120.         IF (c$ = CHR$(13)) THEN c$ = "~"
  121.         _PRINTSTRING (Cursor1.X, Cursor1.Y), c$
  122.     END IF
  123.  
  124.     d$ = TheChain(ID1).Content
  125.     e$ = TheChain(ID2).Content
  126.     IF ((ASC(d$) = 10) OR (ASC(d$) = 13)) THEN d$ = "~"
  127.     IF ((ASC(e$) = 10) OR (ASC(e$) = 13)) THEN e$ = "~"
  128.     IF (ASC(d$) = 32) THEN d$ = "_"
  129.     IF (ASC(e$) = 32) THEN e$ = "_"
  130.  
  131.     IF ((Cursor1.X = Cursor2.X) AND (Cursor1.Y = Cursor2.Y)) THEN COLOR 0, 5 ELSE COLOR 0, 3
  132.     c$ = "(" + LTRIM$(RTRIM$(STR$(Cursor1.X - LeftIndent))) + "," + LTRIM$(RTRIM$(STR$(Cursor1.Y - TopIndent))) + ":" + " " + LTRIM$(RTRIM$(d$)) + " " + LTRIM$(RTRIM$(STR$(ID1))) + ")"
  133.     _PRINTSTRING (2, _HEIGHT), c$
  134.     IF (LinearCount(StartIndex, ID2) > LinearCount(StartIndex, ID1)) THEN
  135.         COLOR 0, 6
  136.         _PRINTSTRING (3 + LEN(c$), _HEIGHT), "(" + LTRIM$(RTRIM$(STR$(Cursor2.X - LeftIndent))) + "," + LTRIM$(RTRIM$(STR$(Cursor2.Y - TopIndent))) + ":" + " " + LTRIM$(RTRIM$(e$)) + " " + LTRIM$(RTRIM$(STR$(ID2))) + ")"
  137.     END IF
  138.  
  139.     COLOR 8, 7
  140.     p = LinearCount(ID1, NthP(ID1, MemLimit + 1))
  141.     q = LinearCount(NthL(ID1, MemLimit + 1), NthP(ID1, MemLimit + 1))
  142.     IF (q = 0) THEN r = 1 ELSE r = 1 - p / q
  143.     _PRINTSTRING (_WIDTH, 1 + INT(r * (_HEIGHT - 1))), "*"
  144.  
  145.     COLOR 15, 0
  146.     SELECT CASE TextWrapping
  147.         CASE 0: d$ = "Square"
  148.         CASE 1: d$ = "Fluid"
  149.         CASE 2: d$ = "None"
  150.     END SELECT
  151.     c$ = "[F6=Save] [F11=Formatting] [F12=Wrapping: " + d$ + "]"
  152.     IF (TextWrapping = 2) THEN c$ = "[F1/2=HScroll] " + c$
  153.     c$ = c$ + STR$(INT(100 * r)) + "%"
  154.     _PRINTSTRING (_WIDTH - LEN(c$), 1), c$
  155.  
  156.     c$ = "[Esc=Sync] [Mouse2=Copy] [Mouse3=Paste]"
  157.     IF (InsertKey = 1) THEN c$ = "[Ins] " + c$
  158.     _PRINTSTRING (_WIDTH - LEN(c$), _HEIGHT), c$
  159.  
  160. SUB Assimilate (a AS STRING)
  161.     ' Load a string to initialize chain.
  162.     FOR k = 1 TO MemLimit
  163.         TheChain(k).Identity = 0
  164.     NEXT
  165.     StartIndex = 1
  166.     PreviousIdentity = BOC
  167.     NextIdentity = NextOpenIdentity(StartIndex)
  168.     FOR k = 1 TO LEN(a)
  169.         j = NextIdentity
  170.         TheChain(j).Identity = j
  171.         TheChain(j).Content = ReFormat$(MID$(a, k, 1))
  172.         TheChain(j).Lagger = PreviousIdentity
  173.         PreviousIdentity = j
  174.         IF (k < LEN(a)) THEN
  175.             NextIdentity = NextOpenIdentity(j)
  176.             TheChain(j).Pointer = NextIdentity
  177.         ELSE
  178.             TheChain(j).Pointer = EOC
  179.         END IF
  180.         PRINT TheChain(j).Content
  181.     NEXT
  182.     ID1 = StartIndex
  183.     ID2 = ID1
  184.  
  185. FUNCTION ReFormat$ (a AS STRING)
  186.     c$ = a
  187.     IF c$ = CHR$(10) THEN c$ = CHR$(13)
  188.     IF c$ = CHR$(9) THEN c$ = "    "
  189.     ReFormat = c$
  190.  
  191. FUNCTION NthP (a AS LONG, b AS LONG)
  192.     ' Returns the address that is b jumps ahead of address a.
  193.     i = a
  194.     IF (i <> EOC) THEN
  195.         k = 0
  196.         j = 0
  197.         DO WHILE (k < b)
  198.             k = k + 1
  199.             j = TheChain(i).Identity
  200.             i = TheChain(j).Pointer
  201.             IF (i = EOC) THEN EXIT DO
  202.         LOOP
  203.     END IF
  204.     NthP = j
  205.  
  206. FUNCTION NthPC (a AS LONG, b AS STRING)
  207.     ' Returns the address holding b first enLinearCountered from a.
  208.     i = a
  209.     DO
  210.         j = TheChain(i).Identity
  211.         i = TheChain(j).Pointer
  212.         IF (TheChain(j).Content = b) THEN EXIT DO
  213.         IF (i = EOC) THEN
  214.             j = BOC
  215.             EXIT DO
  216.         END IF
  217.     LOOP
  218.     NthPC = j
  219.  
  220. FUNCTION NthL (a AS LONG, b AS LONG)
  221.     ' Returns the address that is b jumps behind address a.
  222.     i = a
  223.     k = 0
  224.     DO WHILE k < b
  225.         k = k + 1
  226.         j = TheChain(i).Identity
  227.         i = TheChain(j).Lagger
  228.         IF (i = BOC) THEN EXIT DO
  229.     LOOP
  230.     NthL = j
  231.  
  232. FUNCTION NextOpenIdentity (a AS LONG)
  233.     ' Returns first nonzero identity.
  234.     FOR j = a TO MemLimit
  235.         IF (TheChain(j).Identity = 0) THEN EXIT FOR
  236.     NEXT
  237.     IF (j > MemLimit) THEN
  238.         PRINT "Out of memory: "; MemLimit
  239.         SLEEP
  240.         SYSTEM
  241.     END IF
  242.     NextOpenIdentity = j
  243.  
  244. FUNCTION BackBreak (a AS LONG)
  245.     ' Function for scrolling up.
  246.     j = a
  247.     lastbreak = 0
  248.     c$ = ""
  249.     DO
  250.         IF (j = BOC) THEN EXIT DO
  251.         k = TheChain(j).Lagger
  252.         IF (k = BOC) THEN
  253.             lastbreak = j
  254.             EXIT DO
  255.         END IF
  256.         j = k
  257.         d$ = TheChain(j).Content
  258.         IF ((TextWrapping = 1) AND (d$ = " ")) THEN lastbreak = j
  259.         c$ = d$ + c$
  260.         IF (TextWrapping <> 2) AND (LEN(c$) = TextWidth) THEN EXIT DO
  261.         IF (d$ = CHR$(13)) THEN EXIT DO
  262.     LOOP
  263.     IF (lastbreak <> 0) THEN j = TheChain(lastbreak).Identity
  264.     BackBreak = j
  265.  
  266. SUB InsertBefore (a AS LONG, b AS STRING)
  267.     ' Inserts a single cell before address a in the chain.
  268.     j = NextOpenIdentity(a)
  269.     al = TheChain(a).Lagger
  270.     TheChain(j).Identity = j
  271.     TheChain(j).Pointer = a
  272.     TheChain(j).Lagger = al
  273.     TheChain(j).Content = ReFormat$(b)
  274.     TheChain(a).Lagger = j
  275.     IF (al = BOC) THEN StartIndex = j ELSE TheChain(al).Pointer = j
  276.  
  277. SUB InsertAfter (a AS LONG, b AS STRING)
  278.     ' Inserts a single cell after address a in the chain.
  279.     j = NextOpenIdentity(a)
  280.     ap = TheChain(a).Pointer
  281.     TheChain(j).Identity = j
  282.     TheChain(j).Pointer = ap
  283.     TheChain(j).Lagger = a
  284.     TheChain(j).Content = ReFormat$(b)
  285.     TheChain(a).Pointer = j
  286.     IF (ap <> EOC) THEN TheChain(ap).Lagger = j
  287.  
  288. SUB InsertRange (a AS LONG, b AS STRING)
  289.     ' Inserts a sub-chain anywhere.
  290.     FOR k = 1 TO LEN(b)
  291.         c$ = MID$(b, k, 1)
  292.         CALL InsertBefore(a, c$)
  293.     NEXT
  294.  
  295. SUB UnlinkCell (a AS LONG)
  296.     ' Remove single cell from chain and clear identity.
  297.     ap = TheChain(a).Pointer
  298.     al = TheChain(a).Lagger
  299.     IF ((ap = EOC) AND (al = BOC)) THEN
  300.         TheChain(a).Content = " "
  301.         'ID1 = a
  302.         'ID2 = ID1
  303.     ELSE
  304.         TheChain(a).Identity = 0
  305.         IF ((ap <> EOC) AND (al <> BOC)) THEN
  306.             TheChain(al).Pointer = ap
  307.             TheChain(ap).Lagger = al
  308.         END IF
  309.         IF (ap = EOC) THEN TheChain(al).Pointer = EOC
  310.         IF (al = BOC) THEN
  311.             StartIndex = ap
  312.             TheChain(ap).Lagger = BOC
  313.         END IF
  314.     END IF
  315.  
  316. SUB UnlinkRange (a AS LONG, b AS LONG)
  317.     ' Remove sub-chain and clear identity of each cell.
  318.     bp = TheChain(b).Pointer
  319.     al = TheChain(a).Lagger
  320.     IF ((al = BOC) AND (bp = EOC)) THEN
  321.         CALL UnlinkRange(NthP(a, 2), b)
  322.         TheChain(a).Content = " "
  323.         TheChain(a).Pointer = bp
  324.     ELSE
  325.         k = a
  326.         DO WHILE ((k <> b) AND (k <> EOC))
  327.             TheChain(k).Identity = 0
  328.             k = TheChain(k).Pointer
  329.         LOOP
  330.         TheChain(b).Identity = 0
  331.         TheChain(bp).Lagger = al
  332.         IF (al = BOC) THEN StartIndex = bp ELSE TheChain(al).Pointer = bp
  333.     END IF
  334.  
  335. FUNCTION LinearCount (a AS LONG, b AS LONG)
  336.     ' Returns number of links between two addresses.
  337.     i = a
  338.     k = 0
  339.     DO WHILE (i <> b)
  340.         k = k + 1
  341.         j = TheChain(i).Identity
  342.         i = TheChain(j).Pointer
  343.         IF (i = EOC) THEN EXIT DO
  344.     LOOP
  345.     LinearCount = k
  346.  
  347. FUNCTION Projection$ (a AS LONG, b AS LONG)
  348.     ' Returns the linear content for all address between a and b, inclusive.
  349.     DIM TheReturn AS STRING
  350.     TheReturn = ""
  351.     IF (a = b) THEN
  352.         TheReturn = TheChain(a).Content
  353.     ELSE
  354.         j = a
  355.         DO
  356.             c$ = TheChain(j).Content
  357.             TheReturn = TheReturn + c$
  358.             k = TheChain(j).Pointer
  359.             IF (j = b) THEN EXIT DO
  360.             IF (k = EOC) THEN EXIT DO
  361.             j = k
  362.         LOOP
  363.     END IF
  364.     Projection$ = TheReturn
  365.  
  366. SUB MapText
  367.     IF (TextFormatting = 1) THEN br$ = "~" ELSE br$ = " "
  368.     j = StartIndex
  369.     i = 1
  370.     q$ = ""
  371.     d$ = ""
  372.     DO ' Begin with any left-over text from previous iteration.
  373.         q$ = d$
  374.         d$ = ""
  375.         r = TextWidth - LEN(q$)
  376.         IF (TextWrapping = 2) THEN r = MemLimit + 1
  377.         k1 = NthP(j, r)
  378.         k2 = NthPC(j, CHR$(13))
  379.         c1 = LinearCount(j, k1)
  380.         c2 = LinearCount(j, k2)
  381.         IF (c2 = 0) THEN ' Line is blank-returned.
  382.             k = k2
  383.             q$ = q$ + br$
  384.             j = NthP(k, 2)
  385.         ELSE
  386.             IF (c1 = c2) THEN ' Possible end of chain.
  387.                 k = TheChain(k1).Lagger
  388.                 q$ = q$ + Projection$(j, k)
  389.                 j = NthP(k, 2)
  390.             END IF
  391.             IF (c1 < c2) THEN ' Width limit case (not always maximum).
  392.                 k = k1
  393.                 q$ = q$ + Projection$(j, k)
  394.                 j = NthP(k, 2)
  395.             END IF
  396.             IF (c1 > c2) THEN ' Break return somewhere in line (not first).
  397.                 k = k2
  398.                 q$ = q$ + Projection$(j, TheChain(k).Lagger) + br$
  399.                 n = TheChain(k).Pointer
  400.                 IF (n <> EOC) THEN j = n
  401.             END IF
  402.         END IF
  403.         IF (TextWrapping = 1) THEN ' Wrap text at first space from right, send remainder to next line.
  404.             IF (LEN(q$) >= TextWidth) THEN
  405.                 FOR m = LEN(q$) TO 1 STEP -1
  406.                     c$ = MID$(q$, m, 1)
  407.                     IF (c$ = " ") OR (c$ = "-") THEN
  408.                         q$ = LEFT$(q$, m)
  409.                         EXIT FOR
  410.                     END IF
  411.                     d$ = c$ + d$
  412.                     IF (m = 1) THEN ' Line is too long for allowed space and contains no wrapping characters.
  413.                         q$ = LEFT$(q$, TextWidth)
  414.                         d$ = ""
  415.                         EXIT FOR
  416.                     END IF
  417.                 NEXT
  418.             END IF
  419.         END IF
  420.         LineAsMapped(i) = q$
  421.         i = i + 1
  422.         IF (i >= TextHeight) THEN EXIT DO
  423.         IF (j = k) THEN EXIT DO
  424.     LOOP
  425.     VisibleLines = i - 1
  426.  
  427. FUNCTION StateChange
  428.     DIM TheReturn AS INTEGER
  429.     TheReturn = 0
  430.     MH = 0
  431.         MH1 = _MOUSEBUTTON(1)
  432.         MH2 = _MOUSEBUTTON(2)
  433.         MH3 = _MOUSEBUTTON(3)
  434.     LOOP
  435.     IF (MH1 = -1) THEN ' Move Cursor1.
  436.         MH = 1
  437.         IF (_MOUSEX > LeftIndent) AND (_MOUSEX < TextWidth + LeftIndent + 1) AND (_MOUSEY > TopIndent) AND (_MOUSEY < TopIndent + TextHeight + 1) THEN
  438.             Cursor1.X = _MOUSEX
  439.             q = LeftIndent + LEN(LineAsMapped(_MOUSEY - TopIndent))
  440.             IF (Cursor1.X > q) THEN Cursor1.X = q
  441.             Cursor1.Y = _MOUSEY
  442.             CALL ReassignID1
  443.         END IF
  444.     END IF
  445.     IF (MH2 = -1) THEN ' Move Cursor2 and copy anything between Cursor1 and Cursor2 to clipboard.
  446.         MH = 1
  447.         IF (_MOUSEX > LeftIndent) AND (_MOUSEX < TextWidth + LeftIndent + 1) AND (_MOUSEY > TopIndent) AND (_MOUSEY < TopIndent + TextHeight + 1) THEN
  448.             Cursor2.X = _MOUSEX
  449.             q = LeftIndent + LEN(LineAsMapped(_MOUSEY - TopIndent))
  450.             IF (Cursor2.X > q) THEN Cursor2.X = q
  451.             Cursor2.Y = _MOUSEY
  452.             CALL ReassignID2
  453.             IF (LinearCount(StartIndex, ID2) > LinearCount(StartIndex, ID1)) THEN _CLIPBOARD$ = Projection$(ID1, ID2)
  454.         END IF
  455.     END IF
  456.     IF (MH3 = -1) THEN ' Paste at Cursor1 position.
  457.         MH = 1
  458.         IF (LinearCount(StartIndex, ID2) > LinearCount(StartIndex, ID1)) THEN CALL InsertRange(ID1, _CLIPBOARD$)
  459.     END IF
  460.  
  461.     KH = 0
  462.     KH = _KEYHIT
  463.     ' Bksp
  464.     IF (KH = 8) THEN
  465.         r = TheChain(ID1).Pointer
  466.         q = TheChain(ID1).Lagger
  467.         CALL UnlinkCell(ID1)
  468.         IF ((r = EOC) AND (q = BOC)) THEN
  469.         ELSE
  470.             IF (q <> BOC) THEN ID1 = q ELSE ID1 = r
  471.             IF (r = EOC) THEN ID2 = ID1
  472.         END IF
  473.     END IF
  474.     ' Tab
  475.     IF (KH = 9) THEN CALL InsertRange(ID1, "    ")
  476.     ' Esc
  477.     IF (KH = 27) THEN
  478.         IF (ID2 <> ID1) THEN ID2 = ID1 ELSE ID2 = NthL(ID2, MemLimit + 1)
  479.     END IF
  480.     ' Enter, Alphanumerics
  481.     IF (KH = 13) OR ((KH >= 32) AND (KH <= 126)) THEN
  482.         IF (InsertKey = -1) THEN
  483.             IF (ID1 = ID2) THEN
  484.                 CALL InsertBefore(ID1, LTRIM$(RTRIM$(CHR$(KH))))
  485.             ELSE
  486.                 CALL InsertAfter(ID1, LTRIM$(RTRIM$(CHR$(KH))))
  487.                 ID1 = NthP(ID1, 2)
  488.             END IF
  489.         ELSE
  490.             TheChain(ID1).Content = LTRIM$(RTRIM$(CHR$(KH)))
  491.             IF (ID1 = ID2) THEN
  492.                 ID1 = NthP(ID1, 2)
  493.                 ID2 = ID1
  494.             ELSE
  495.                 ID1 = NthP(ID1, 2)
  496.             END IF
  497.         END IF
  498.     END IF
  499.     ' F1
  500.     IF (KH = 15104) THEN
  501.         IF (TextWrapping = 2) THEN
  502.             HScroll = HScroll - 1
  503.             IF (HScroll < 1) THEN HScroll = 1
  504.             CALL ReassignID1
  505.             CALL ReassignID2
  506.         END IF
  507.     END IF
  508.     ' F2
  509.     IF (KH = 15360) THEN
  510.         IF (TextWrapping = 2) THEN
  511.             HScroll = HScroll + 1
  512.             CALL ReassignID1
  513.             CALL ReassignID2
  514.         END IF
  515.     END IF
  516.     ' F5
  517.     IF (KH = 16128) THEN
  518.         q$ = Projection$(NthL(ID1, MemLimit + 1), NthP(ID1, MemLimit + 1))
  519.         Assimilate q$
  520.     END IF
  521.     ' F4
  522.     IF (KH = 15872) THEN
  523.         'CALL InsertRange(NthP(ID2, 2), "=" + SxriptEval$(Projection(ID1, ID2)))
  524.     END IF
  525.     ' F6
  526.     IF (KH = 16384) THEN
  527.         OPEN FileName$ FOR OUTPUT AS #1
  528.         q$ = Projection$(NthL(ID1, MemLimit + 1), NthP(ID1, MemLimit + 1))
  529.         PRINT #1, q$
  530.         CLOSE #1
  531.     END IF
  532.     ' F7
  533.     IF (KH = 16640) THEN
  534.         CALL ConvertToGrid
  535.         CALL GOL
  536.         CALL ConvertFromGrid
  537.     END IF
  538.     ' F8
  539.     IF (KH = 16896) THEN
  540.  
  541.     END IF
  542.     ' Home
  543.     IF (KH = 18176) THEN
  544.         IF (TextWrapping = 2) THEN HScroll = 1
  545.         Cursor1.X = LeftIndent + 1
  546.         CALL ReassignID1
  547.     END IF
  548.     ' UpArrow
  549.     IF (KH = 18432) THEN
  550.         IF (Cursor1.Y > TopIndent + 1) THEN
  551.             Cursor1.Y = Cursor1.Y - 1
  552.         ELSE
  553.             StartIndex = BackBreak(StartIndex)
  554.         END IF
  555.         q = LEN(LineAsMapped(Cursor1.Y - TopIndent)) + 1
  556.         IF (Cursor1.X > q) THEN Cursor1.X = q
  557.         CALL ReassignID1
  558.     END IF
  559.     ' LeftArrow
  560.     IF (KH = 19200) THEN
  561.         ID1 = NthL(ID1, 2)
  562.         IF (TextWrapping = 2) THEN
  563.             IF (Cursor1.X = LeftIndent + 1) THEN
  564.                 IF (HScroll > 1) THEN
  565.                     HScroll = HScroll - 1
  566.                 ELSE
  567.                     j = Cursor1.Y - TopIndent - 1
  568.                     IF (j >= 1) THEN
  569.                         k = LEN(LineAsMapped(j)) - TextWidth + 1
  570.                         IF (k >= 1) THEN
  571.                             HScroll = k
  572.                         END IF
  573.                     END IF
  574.                 END IF
  575.             END IF
  576.         END IF
  577.     END IF
  578.     ' RightArrow
  579.     IF (KH = 19712) THEN
  580.         ID1 = NthP(ID1, 2)
  581.         IF (TextWrapping = 2) THEN
  582.             m = Cursor1.X - LeftIndent
  583.             n = LEN(LineAsMapped(Cursor1.Y - TopIndent)) - HScroll + 1
  584.             IF (m >= TextWidth) THEN
  585.                 HScroll = HScroll + 1
  586.                 CALL ReassignID1
  587.             END IF
  588.             IF (m >= n) THEN
  589.                 j = Cursor1.Y - TopIndent + 1
  590.                 IF (j <= TextHeight) THEN
  591.                     HScroll = 1
  592.                 END IF
  593.             END IF
  594.         END IF
  595.     END IF
  596.     ' End
  597.     IF (KH = 20224) THEN
  598.         Cursor1.X = LeftIndent + LEN(LineAsMapped(Cursor1.Y - TopIndent))
  599.         CALL ReassignID1
  600.         IF (TextWrapping = 2) THEN
  601.             q = LEN(LineAsMapped(Cursor1.Y - TopIndent)) - TextWidth + 1
  602.             IF (q >= 1) THEN HScroll = q
  603.         END IF
  604.     END IF
  605.     ' DownArrow
  606.     IF (KH = 20480) THEN
  607.         IF (Cursor1.Y = TopIndent + VisibleLines) THEN
  608.             IF (VisibleLines > 1) THEN
  609.                 StartIndex = NthP(StartIndex, LEN(LineAsMapped(1)) + 1)
  610.                 CALL MapText
  611.             END IF
  612.         ELSE
  613.             Cursor1.Y = Cursor1.Y + 1
  614.         END IF
  615.         q = LEN(LineAsMapped(Cursor1.Y - TopIndent)) + 1
  616.         IF (Cursor1.X > q) THEN
  617.             Cursor1.X = q
  618.         END IF
  619.         CALL ReassignID1
  620.     END IF
  621.     ' Insert
  622.     IF (KH = 20992) THEN
  623.         InsertKey = -InsertKey
  624.     END IF
  625.     ' Del
  626.     IF (KH = 21248) THEN
  627.         IF (LinearCount(StartIndex, ID2) > LinearCount(StartIndex, ID1)) THEN
  628.             r = TheChain(ID2).Pointer
  629.             q = TheChain(ID1).Lagger
  630.             p = ID1
  631.             CALL UnlinkRange(ID1, ID2)
  632.             IF ((r = EOC) AND (q = BOC)) THEN
  633.                 ID1 = p
  634.                 ID2 = ID1
  635.                 StartIndex = p
  636.             ELSE
  637.                 IF (q <> BOC) THEN ID1 = q ELSE ID1 = r
  638.                 ID2 = NthP(ID1, 2)
  639.             END IF
  640.         END IF
  641.     END IF
  642.     ' F11
  643.     IF (KH = 34048) THEN TextFormatting = -TextFormatting
  644.     ' F12
  645.     IF (KH = 34304) THEN
  646.         TextWrapping = TextWrapping + 1
  647.         IF (TextWrapping > 2) THEN TextWrapping = 0
  648.         ID1 = StartIndex
  649.         ID2 = ID1
  650.         HScroll = 1
  651.     END IF
  652.     ' Cursor sync and autoscrolling.
  653.     IF ((MH <> 0) OR (KH > 0)) THEN
  654.         TheReturn = 1
  655.         CALL MapText
  656.         CALL CalibrateCursor(ID1)
  657.         CALL CalibrateCursor(ID2)
  658.         IF (Cursor1.Y > TopIndent + TextHeight - 1) THEN StartIndex = NthP(StartIndex, LEN(LineAsMapped(1)) + 1)
  659.     END IF
  660.     StateChange = TheReturn
  661.  
  662. SUB CalibrateCursor (a AS LONG)
  663.     ' Place Cursor under ID on rendered line.
  664.     s = StartIndex
  665.     IF ((TextWrapping = 2) AND (HScroll > 1)) THEN s = NthP(s, HScroll)
  666.     c = LinearCount(s, a)
  667.     k = 0
  668.     FOR j = 1 TO VisibleLines
  669.         n = LEN(LineAsMapped(j))
  670.         IF (k + n < c) THEN
  671.             k = k + n
  672.         ELSE
  673.             i = c - k + 1
  674.             EXIT FOR
  675.         END IF
  676.     NEXT
  677.     IF (i >= LeftIndent + LEN(LineAsMapped(j))) THEN
  678.         IF (j < VisibleLines) THEN
  679.             i = LeftIndent
  680.             j = j + 1
  681.         ELSE
  682.             i = LeftIndent + LEN(LineAsMapped(j))
  683.         END IF
  684.     END IF
  685.     IF (a = ID1) THEN
  686.         Cursor1.X = LeftIndent + i
  687.         Cursor1.Y = TopIndent + j
  688.     END IF
  689.     IF (a = ID2) THEN
  690.         Cursor2.X = LeftIndent + i
  691.         Cursor2.Y = TopIndent + j
  692.     END IF
  693.  
  694. FUNCTION FindID (a AS INTEGER, b AS LONG)
  695.     ' Find identity under a map location.
  696.     RelX = a - LeftIndent
  697.     RelY = b - TopIndent
  698.     FOR k = 1 TO RelY - 1
  699.         t = t + LEN(LineAsMapped(k))
  700.     NEXT
  701.     t = t + RelX
  702.     FindID = t
  703.  
  704. SUB ReassignID1
  705.     ' Reassign identity under Cursor1.
  706.     ID1 = NthP(StartIndex, FindID(Cursor1.X, Cursor1.Y) + (HScroll - 1))
  707.  
  708. SUB ReassignID2
  709.     ' Reassign identity under Cursor2.
  710.     ID2 = NthP(StartIndex, FindID(Cursor2.X, Cursor2.Y) + (HScroll - 1))
  711.  
  712. SUB ConvertToGrid
  713.     FOR j = 1 TO VisibleLines
  714.         c$ = LineAsMapped(j)
  715.         FOR i = 1 TO LEN(c$) - 1 ' BR offset to exclude break return at line end.
  716.             FunGrid(i, j, 1) = MID$(c$, i, 1)
  717.         NEXT
  718.     NEXT
  719.  
  720. SUB ConvertFromGrid
  721.     q$ = ""
  722.     FOR j = 1 TO VisibleLines
  723.         FOR i = 1 TO LEN(LineAsMapped(j)) - 1
  724.             q$ = q$ + FunGrid(i, j, 1)
  725.         NEXT
  726.         q$ = q$ + CHR$(13) ' Undoes BR offset.
  727.     NEXT
  728.     Assimilate q$
  729.  
  730. SUB GOL
  731.     FOR j = 1 TO VisibleLines
  732.         FOR i = 1 TO LEN(LineAsMapped(j)) - 1
  733.             c$ = FunGrid(i, j, 1)
  734.             IF (c$ = " ") THEN c$ = "0" ELSE c$ = "1"
  735.             FunGrid(i, j, 1) = c$
  736.             FunGrid(i, j, 2) = c$
  737.         NEXT
  738.     NEXT
  739.     FOR j = 2 TO VisibleLines - 2 ' BR offset.
  740.         FOR i = 2 TO LEN(LineAsMapped(j)) - 2 ' BR offset.
  741.             c$ = FunGrid(i, j, 1)
  742.             a1 = VAL(FunGrid(i - 1, j + 1, 1))
  743.             a2 = VAL(FunGrid(i, j + 1, 1))
  744.             a3 = VAL(FunGrid(i + 1, j + 1, 1))
  745.             a4 = VAL(FunGrid(i - 1, j, 1))
  746.             a6 = VAL(FunGrid(i + 1, j, 1))
  747.             a7 = VAL(FunGrid(i - 1, j - 1, 1))
  748.             a8 = VAL(FunGrid(i, j - 1, 1))
  749.             a9 = VAL(FunGrid(i + 1, j - 1, 1))
  750.             t = a1 + a2 + a3 + a4 + a6 + a7 + a8 + a9
  751.             IF (c$ = "1") THEN
  752.                 SELECT CASE t
  753.                     CASE IS < 2
  754.                         FunGrid(i, j, 2) = "0"
  755.                     CASE 2
  756.                         FunGrid(i, j, 2) = "1"
  757.                     CASE 3
  758.                         FunGrid(i, j, 2) = "1"
  759.                     CASE IS > 3
  760.                         FunGrid(i, j, 2) = "0"
  761.                 END SELECT
  762.             ELSE
  763.                 IF (t = 3) THEN FunGrid(i, j, 2) = "1"
  764.             END IF
  765.         NEXT
  766.     NEXT
  767.     FOR j = 1 TO VisibleLines
  768.         FOR i = 1 TO LEN(LineAsMapped(j)) - 1
  769.             c$ = FunGrid(i, j, 2)
  770.             IF (c$ = "0") THEN c$ = " " ELSE c$ = CHR$(219)
  771.             FunGrid(i, j, 1) = c$
  772.             FunGrid(i, j, 2) = c$
  773.         NEXT
  774.     NEXT
  775.  
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: qXed: linked list text editor
« Reply #35 on: September 30, 2018, 09:43:03 am »
Well that is one very interesting way to go with an editor!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: qXed: linked list text editor
« Reply #36 on: October 06, 2018, 02:08:25 pm »
Heya all,

Made a pretty fat update that is best kept at the top. I direct you here for the latest: https://www.qb64.org/forum/index.php?topic=597
You're not done when it works, you're done when it's right.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: qXed: linked list text editor
« Reply #37 on: October 08, 2018, 11:19:38 am »
Heya folks,

I want to take some people back to a painful memory of 2014, following the IRC bot wars. In that struggle, I attempted to create an end-all SCREEN 0 program that would perform so many essential functions that a person would never want to close it. In certain ways I succeeded back then, as my go-to IRC client for over a year was an instance of the handmade program to which I'm alluding, the notorious MathBlab. You could do anything but make toast - go online, play poker, evaluate LISP expressions a la qbguy, yada yada - all that stuff. The thing still works, but I'm never pasting the code again under my own name. The guys at #qb64 on irc.freenode.net are still traumatized by the whole thing (mainly the ability to public test Eliza the therapist). See below for a screenshot.

Years later I find my projects at a similar collision point, but the pieces are not as crappy this time. The Sxript thing has gone through a total rewrite since then and is well-trusted, all essential web stuff (for my purposes) has been abstracted into Sprezzo. With a universal SCREEN 0 slate like qXed, I can see these coming together to form a QB64 approximation of emacs. See the second screenshot (my awesome paint skills). (There is one connection missing, and that is between Fellippe's InForm and a general way to handle text. That is being cooked behind the scenes - give it a few weeks or months.)

As for the connections that are marked, you can see why we try to make programs that interact nicely with other ones. Certain combinations give calculators, messaging apps, you see the idea. When three lines collide however, it's time for a new node. The square in the middle sounds suspiciously like the old MathBlab program. So... I have no choice. Expect a web-enabled does-lots-of-screen-zero-stuff program to emerge on this thread next.
mathblab.png
* mathblab.png (Filesize: 74.17 KB, Dimensions: 1366x768, Views: 301)
diagram.png
* diagram.png (Filesize: 20.49 KB, Dimensions: 755x561, Views: 294)
You're not done when it works, you're done when it's right.