diff --git a/temp.txt b/temp.txt index 72bd141..93b4cca 100644 --- a/temp.txt +++ b/temp.txt @@ -1,172 +1 @@ -structure GlDraw = -struct - open CML - open DrawMsg - - (* The name doesn't make it clear, but this structure - * couples GLFW and OpenGL. - * I'm not sure if I will use native windowing systems - * or other graphics APIs at a later stage, - * but the current priority is GLFW + OpenGL. - * *) - type t = - { textVertexBuffer: Word32.word - , textProgram: Word32.word - , textDrawLength: int - , window: MLton.Pointer.t - } - - fun createShader (shaderType, shaderString) = - let - val shader = Gles3.createShader shaderType - val _ = Gles3.shaderSource (shader, shaderString) - val _ = Gles3.compileShader shader - in - shader - end - - fun createProgram (vertexShader, fragmentShader) = - let - val program = Gles3.createProgram () - val _ = Gles3.attachShader (program, vertexShader) - val _ = Gles3.attachShader (program, fragmentShader) - val _ = Gles3.linkProgram program - in - program - end - - fun create window = - let - (* create vertex buffer, program, etc. for text. *) - val textVertexBuffer = Gles3.createBuffer () - val xyzRgbVertexShader = createShader - (Gles3.VERTEX_SHADER, GlShaders.xyzRgbVertexShaderString) - - val rgbFragmentShader = createShader - (Gles3.FRAGMENT_SHADER, GlShaders.rgbFragmentShaderString) - - val textProgram = createProgram (xyzRgbVertexShader, rgbFragmentShader) - - (* clean up shaders which are no longer needed once progran is linked. *) - val _ = Gles3.deleteShader xyzRgbVertexShader - val _ = Gles3.deleteShader rgbFragmentShader - - (* because we only have a single vertex buffer, - * we only need to bind and set attributes once. *) - val _ = Gles3.bindBuffer textVertexBuffer - - (* enable xyz component from uploaded array *) - val _ = Gles3.vertexAttribPointer (0, 3, 6, 0) - val _ = Gles3.enableVertexAttribArray 0 - (* enable rgb component from uploaded array *) - val _ = Gles3.vertexAttribPointer (1, 3, 6, 12) - val _ = Gles3.enableVertexAttribArray 1 - - val _ = Gles3.useProgram textProgram - in - { textVertexBuffer = textVertexBuffer - , textProgram = textProgram - , textDrawLength = 0 - , window = window - } - end - - fun uploadText (shellState: t, vec) = - let - val {textVertexBuffer, textProgram, textDrawLength = _, window} = - shellState - - val _ = Gles3.bufferData (vec, Vector.length vec, Gles3.STATIC_DRAW) - val newTextDrawLength = Vector.length vec div 6 - in - { textVertexBuffer = textVertexBuffer - , textProgram = textProgram - , textDrawLength = newTextDrawLength - , window = window - } - end - - fun draw (drawObject: t) = - let - val {textVertexBuffer, textDrawLength, textProgram, window = _} = - drawObject - in - Gles3.drawArrays (Gles3.TRIANGLES, 0, textDrawLength) - end - - fun yank (shellState: t, str) = - let - (* print when text is yanked *) - val msg = "|" ^ String.toCString str ^ "|\n" - val () = print msg - val () = Glfw.setClipboardString (#window shellState, str) - in - shellState - end - - fun consumeDrawEvent (shellState, msg) = - let - val {textVertexBuffer, textProgram, window, textDrawLength = _, ...} = - shellState - in - case msg of - DRAW_TEXT textVec => uploadText (shellState, textVec) - | YANK str => yank (shellState, str) - end - - local - fun loop (pos, msgVec, shellState) = - if pos = Vector.length msgVec then - shellState - else - let - val msg = Vector.sub (msgVec, pos) - val shellState = consumeDrawEvent (shellState, msg) - in - loop (pos + 1, msgVec, shellState) - end - in - fun consumeDrawEvents shellState = - loop (0, DrawMailbox.getMessagesAndClear (), shellState) - end - - local - fun updateLoop (pos, msgVec, app) = - if pos = Vector.length msgVec then - app - else - let - val msg = Vector.sub (msgVec, pos) - val app = Updater.update (app, msg) - in - updateLoop (pos + 1, msgVec, app) - end - in - fun update app = - updateLoop (0, InputMailbox.getMessagesAndClear (), app) - end - - fun helpLoop (app, shellState as {window, ...}: t) = - case Glfw.windowShouldClose window of - false => - let - val shellState = consumeDrawEvents shellState - - val _ = Gles3.clearColor (0.97, 0.95, 0.937, 1.0) - val _ = Gles3.clear () - - val app = update app - val _ = draw shellState - - val _ = Glfw.swapBuffers window - val _ = Glfw.waitEvents () - in - helpLoop (app, shellState) - end - | true => Glfw.terminate () - - fun loop (app, window) = - let val shellState = create window - in helpLoop (app, shellState) - end -end +h ello world diff --git a/test/normal-delete.sml b/test/normal-delete.sml index 43e581c..76594f8 100644 --- a/test/normal-delete.sml +++ b/test/normal-delete.sml @@ -1320,6 +1320,246 @@ struct end) ] + val deDelete = describe "delete motion 'de'" + [ test + "deletes last char and moves cursor back by one \ + \when used on last char of last word in buffer \ + \and buffer ends with a newline preceded by a non-newline" + (fn _ => + let + (* arrange *) + val originalString = "hello world\n" + val originalIdx = String.size originalString - 2 + + val app = TestUtils.init originalString + val app = AppWith.idx (app, originalIdx) + + (* act *) + val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "de") + + (* assert *) + val expectedString = "hello worl\n" + val actualString = LineGap.toString buffer + + val expectedIdx = String.size expectedString - 2 + in + Expect.isTrue + (expectedString = actualString andalso expectedIdx = cursorIdx) + end) + , test "deletes second word as expected when there are three words" (fn _ => + let + (* arrange *) + val originalString = "hello world again\n" + + val app = TestUtils.init originalString + + (* all the different positions the cursor can be + * on the second word *) + val app1 = AppWith.idx (app, 6) + val app2 = AppWith.idx (app, 7) + val app3 = AppWith.idx (app, 8) + val app4 = AppWith.idx (app, 9) + val app5 = AppWith.idx (app, 10) + + (* act *) + val newApp1 = TestUtils.updateMany (app1, "de") + val newApp2 = TestUtils.updateMany (app2, "de") + val newApp3 = TestUtils.updateMany (app3, "de") + val newApp4 = TestUtils.updateMany (app4, "de") + val newApp5 = TestUtils.updateMany (app5, "de") + + (* assert *) + val expectedString1 = "hello again\n" + val expectedString2 = "hello w again\n" + val expectedString3 = "hello wo again\n" + val expectedString4 = "hello wor again\n" + val expectedString5 = "hello worl\n" + + val actualString1 = LineGap.toString (#buffer newApp1) + val actualString2 = LineGap.toString (#buffer newApp2) + val actualString3 = LineGap.toString (#buffer newApp3) + val actualString4 = LineGap.toString (#buffer newApp4) + val actualString5 = LineGap.toString (#buffer newApp5) + + val stringsAreExpected = + expectedString1 = actualString1 + andalso expectedString2 = actualString2 + andalso expectedString3 = actualString3 + andalso expectedString4 = actualString4 + andalso expectedString5 = actualString5 + + val expectedCursor1 = 6 + val expectedCursor2 = 7 + val expectedCursor3 = 8 + val expectedCursor4 = 9 + val expectedCursor5 = 9 + + val actualCursor1 = #cursorIdx newApp1 + val actualCursor2 = #cursorIdx newApp2 + val actualCursor3 = #cursorIdx newApp3 + val actualCursor4 = #cursorIdx newApp4 + val actualCursor5 = #cursorIdx newApp5 + + val cursorsAreExpected = + expectedCursor1 = actualCursor1 + andalso expectedCursor2 = actualCursor2 + andalso expectedCursor3 = actualCursor3 + andalso expectedCursor4 = actualCursor4 + andalso expectedCursor5 = actualCursor5 + in + Expect.isTrue (stringsAreExpected andalso cursorsAreExpected) + end) + , test + "deletes from cursor until newline when on last word \ + \before a newline and another word follows that newline" + (fn _ => + let + (* arrange *) + val originalString = "hello\nworld\nagain\n" + val app = TestUtils.init originalString + val app = AppWith.idx (app, 1) + + (* act *) + val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "de") + + (* assert *) + val expectedString = "h\nworld\nagain\n" + (* moves cursor back by one when next char is newline *) + val expectedCursor = 0 + + val actualString = LineGap.toString buffer + + val stringIsExpected = expectedString = actualString + val cursorIsExpected = expectedCursor = cursorIdx + in + Expect.isTrue (stringIsExpected andalso cursorIsExpected) + end) + , test + "deletes until first punctuation char when on an alpha char \ + \and there is no space between alpha and punctuation" + (fn _ => + let + (* arrange *) + val originalString = "hello!world!again\n" + val app = TestUtils.init originalString + + (* act *) + val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "de") + + (* assert *) + val expectedString = "!world!again\n" + val expectedCursor = 0 + + val actualString = LineGap.toString buffer + + val stringIsExpected = expectedString = actualString + val cursorIsExpected = expectedCursor = cursorIdx + in + Expect.isTrue (stringIsExpected andalso cursorIsExpected) + end) + , test + "deletes until first alpha char when on punctuation \ + \and there is no space between punctuation and alpha" + (fn _ => + let + (* arrange *) + val originalString = "!#%&QWERTY#!\n" + val app = TestUtils.init originalString + + (* act *) + val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "de") + + (* assert *) + val expectedString = "QWERTY#!\n" + val expectedCursor = 0 + + val actualString = LineGap.toString buffer + + val stringIsExpected = expectedString = actualString + val cursorIsExpected = expectedCursor = cursorIdx + in + Expect.isTrue (stringIsExpected andalso cursorIsExpected) + end) + , test + "deletes end of next world \ + \when cursor is on space and next char is alpha" + (fn _ => + let + (* arrange *) + val originalString = "h ello world\n" + val app = TestUtils.init originalString + val app = AppWith.idx (app, 1) + + (* act *) + val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "de") + + (* assert *) + val expectedString = "h world\n" + val actualString = LineGap.toString buffer + val expectedCursor = 1 + + val stringIsExpected = expectedString = actualString + val cursorIsExpected = expectedCursor = cursorIdx + in + Expect.isTrue (stringIsExpected andalso cursorIsExpected) + end) + , test + "deletes next world \ + \when cursor is on space, many spaces are ahead, \ + \and first char after spaces is alpha" + (fn _ => + let + (* arrange *) + val originalString = "h ello world\n" + val app = TestUtils.init originalString + val app = AppWith.idx (app, 3) + + (* act *) + val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "de") + + (* assert *) + val expectedString = "h world\n" + val actualString = LineGap.toString buffer + val expectedCursor = 3 + + val stringIsExpected = expectedString = actualString + val cursorIsExpected = expectedCursor = cursorIdx + in + Expect.isTrue (stringIsExpected andalso cursorIsExpected) + end) + , test + "deletes next word \ + \when cursor is on space and next non-space char is punctuation" + (fn _ => + let + (* arrange *) + val originalString = "! @#$% world\n" + val app = TestUtils.init originalString + val app = AppWith.idx (app, 2) + + (* act *) + val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "de") + + (* assert *) + val expectedString = "! world\n" + val actualString = LineGap.toString buffer + val expectedCursor = 2 + + val stringIsExpected = expectedString = actualString + val cursorIsExpected = expectedCursor = cursorIdx + in + Expect.isTrue (stringIsExpected andalso cursorIsExpected) + end) + ] + val tests = - [dhDelete, dlDelete, djDelete, ddDelete, dkDelete, dwDelete, dWDelete] + [ dhDelete + , dlDelete + , djDelete + , ddDelete + , dkDelete + , dwDelete + , dWDelete + , deDelete + ] end