Coder Social home page Coder Social logo

varabyte / kotter Goto Github PK

View Code? Open in Web Editor NEW
531.0 531.0 16.0 2.24 MB

A declarative, Kotlin-idiomatic API for writing dynamic console applications.

License: Apache License 2.0

Kotlin 100.00%
ansi ansi-colors console console-colors kotlin kotlin-jvm kotlin-linux kotlin-macos kotlin-mingw kotlin-multiplatform reactive terminal terminal-input

kotter's People

Contributors

bitspittle avatar ellet0 avatar grnt426 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

kotter's Issues

Handle control C

We should restore the cursor when the user presses Ctrl+C, and probably add handler methods to KonsoleBlock and KonsoleApp that get triggered as well so users can clean up if it happens.

Add an API for drawing a box

Something like

box(WIDTH, HEIGHT, x, y, "TEXT")

where

box(10, 10, 3, 5, "Hello")

would render (assume X's are spaces):

XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXHelloXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX

This would be useful in the robot example but also for something like, say, a "screensaver", like a text string that bounces around the console.

But this is low priority, and honestly may be a very niche case.

Add onFinishing callback

so you can set state one last time before the block finishes.

The blinking cursor, for example, should internally use this, and turn off its blinker, so it isn't recorded in static history for all time.

Add lots of interesting animation effects

For a CLI, these ideas may be overkill, but writing them down as food for thought.

Bounce vs. loop (i.e. A, B, C, D, C, B, A, B, ...)
Custom animation frame lengths
Easing
A library of common animations

add generateSideEffect

Occasionally, a dynamic active block may want to generate static text which should go into the history. So something like:

Initially:

Compiling...
Thread #1: foo/whatever.kt
Thread #2: bar/somethingelse.kt
Thread #3: idle
Thread #3: baz/morecode.kt

Then later:

Compiled foo/whatever.kt
Compiled bar/somethingelse.kt

Compiling...
Thread #1: foo/lastone.kt
Thread #2: idle
Thread #3: idle
Thread #3: baz/morecode.kt

More later:

Compiled foo/whatever.kt
Compiled bar/somethingelse.kt
Compiled baz/morecode.kt

Compiling...
Thread #1: foo/lastone.kt
Thread #2: idle
Thread #3: idle
Thread #3: idle

And finally:

Compiled foo/whatever.kt
Compiled bar/somethingelse.kt
Compiled baz/morecode.kt
Compiled foo/lastone.kt

Compiling... DONE!
Compilation took 15.2 seconds

The idea being that even while one block is still active, it can send output to the static history:

            | Compiled foo/whatever.kt
Static      | Compiled bar/somethingelse.kt
            | Compiled baz/morecode.kt

            | Compiling...
            | Thread #1: foo/lastone.kt
Active      | Thread #2: idle
            | Thread #3: idle
            | Thread #3: idle

You can fake this by having the WHOLE thing be active, and just have the static part really be part of the active part, maybe a bunch of lines that get prepended, but the concern is for something like a compiler working on thousands of files, this could probably add up into many many many lines that Konsole is repainting unecessarily.

The API would probably look something like this (although possibly a better name?)

konsole {
   /* ... this is KonsoleBlock@1234 */
 }.run {
    generateSideEffect {
        /* ... this is KonsoneBlock@4567 and it is only run once ... */
    }
 }

Hide cursor when you've left the konsole block

While active:

Please enter your first name: John_

What should happen after pressing enter:

Please enter your first name: John
Please enter your last name: _

What's happening right now:

Please enter your first name: John_
Please enter your last name: _

Have a way to set colors / effects via enumerated type?

Right now we have

red { text(...) }
green { text(...) }

but imagine you wanted to change the color based on some enumerated type. It's awkward!

// Option 1
when(state) {
  ALIVE -> white { text("*") }
  DYING -> red { text("*") }
  DEAD -> black { text("*") }
}

// Option 2
scopedState {
   when(state) {
      ALIVE -> white()
      DYING -> red()
      DEAD -> black()
   }
   text("*")
}

If we had an option that took an enum, we could do something like:

val c = when(state) {
  ALIVE -> Colors.Fg.WHITE
  DYING -> Colors.Fg.RED
  DEAD -> Colors.Fg.BLACK
}
color(c) { text("*") }

and you might even have a set of custom themes, with "fgColor" and "bgColor" you can reference everywhere this way:

fgColor { text("...") }
bgColor { text("...") }

Of course, you could also add fgColor and bgColor functions in your codebase yourself:

var theme = ...

fun KonsoleScope.fgColor(block: KonsoleScope.() -> Unit) {
   scopedState {
      when(theme) { ... }
   }
}

fun KonsoleScope.bgColor(...) { ... }

so maybe it's not critical to figure this out right now

Virtual Console should add at least two newlines between itself and the final text on exit

Approach 1: Two newlines

textLine("Last line")
textLine()

Outputs on exit:

Last line

(This session ended blah blah blah)

Everything below this point should do the same.


Approach 2: One newline

textLine("Last line")

Outputs on exit:

Last line
(This session ended blah blah blah)

Approach 2: No newlines

text("Last line")

Outputs on exit:

Last line
(This session ended blah blah blah)

Make requestRerender non-blocking

Instead, KonsoleBlock should keep a list of futures

rerenderLock = ReenterantLock()
rerenderRequests = mutableListOf<Future<*>>

rerenderLock.withLock {
if (rerenderRequests.length == 2) return
rerenderRequests.add(executor.submit { ... })
}

In theory that should work? We always have current work and (optional) followup work. If more "rerenderRequests" come in and we already have followupWork scheduled, we don't need to add it because they're already covered

README: Add gifs

This could be useful for highlighting various examples, especially those with animations.

Stop animation timers if an animation wasn't rendered last frame

Option 1: Automatically reset animation back to 0 when not referenced for a frame

We could possibly do this by keeping track of all animations referenced each render pass and checking if any ones weren't referenced the next time around.

Even if we could do this though, should we?

Option 2: Add a "reset" method to the KonsoleAnim class which users can trigger in the run block if they want to.

Audit class documentation and API

Read class docs with fresh eyes, and make sure every public method is documented, except for the most obvious.

Also, trim unused methods and audit internal vs public vs private

Add architecture doc

Discuss the top level packages (runtime, foundation, and terminal) and the important role played by the ConcurrentScopedData class.

Allow addTimer to take a key value for uniqueness

Currently in Snake I'm doing something like:

var firstMove = true
level.snake.onMoved = {
   if (firstMove) {
      firstMove = false
      addTimer(KonsoleAnim.ONE_FRAME_60FPS, repeat = true) {
         ...
      }
   }
}

which could possibly be simplified to:

level.snake.onMoved = {
   addTimer(KonsoleAnim.ONE_FRAME_60FPS, repeat = true, key = level.snake) {
      ...
   }
}

In other words, if a timer with the particular key is already found, don't add it again.

Support input completions

Maybe

konsole(inputCompletions = setOf("yes", "no")) {
   textLine("Do you like this example?")
   textLine("> $input")
}

Add support for clearing text effects

Turns out you can do this afterall...

39m - clear fg
49m - clear bg
21m - clear bold
24m - clear underline
29m - clear strikethrough
27m - clear inverted

This should have new commands, support for them in the virtual terminal, new API functions, and.... updates to KonsoleState? Can we clean up the logic in TextSupport?

Add user input support

Typing characters, left/right, backspace, del, HOME/END, ENTER

onInputChanged
onInputEntered
onKeyPressed

  • For Virtual Terminal
  • For Linux Terminal

Split up packages into different modules

Now that we have a consistent set of rules, namely

Terminal depends on Runtime
Foundation depends on Terminal + Runtime

it would be best to break things up into three modules to enforce we don't accidentally add a class in the future which breaks them.

(Or is there some Java 9 jigsaw thing we can do?)

p { ... } may get confused by ansi escape codes

Paragraph is supposed to be smart about detecting newlines, and not adding more unecessarily, so:

textLine("Hello")
p { textLine("Paragraph") }
textLine("World")

is supposed to print out:

Hello

Paragraph

World

but adding ANSI codes screws it up:

red { text("Hello") }
p { green { text("Paragraph") } }
blue { text("World") }
Hello


Paragraph


World

Do we want to parse text into nodes so we can skip over non-text nodes?

(Maybe) Rename KonsoleScope to RenderScope

It seems more descriptive, but I should sleep on it.

Also "KonsoleScope.Lifecycle" feels hard to pin down as a short lived lifecycle while "RenderScope.Lifecycle" communicates it more effectively.

Throw an exception if a konsole block is created but never run

We can throw the exception either when a new konsole block is defined or if the konsoleApp exists:

konsole {
   textLine("...")
}  // <--- whoops no run

konsole { // <--- Throw exception here
   textLine("...")
}.run()

The thought is, if you don't run the block, it's probably a mistake. That being said, can we think of cases where someone might define a block that is optionally run? Maybe.

Strip ansi codes out of calls to textLine

Kotter aims to be opinionated about its ansi output and (via the Virtual Console) the subset of ansi it supports, so don't let users add whatever they want into their strings

Audit input keys

Currently we support some control keys (ENTER, HOME, etc.) but we should support all of them (TAB, F1, CTRL) and maybe even include isCtrl, isAlt, isShift methods on the onKeyPressed event.

Consume block after running

There should be a boolean which is set to true, after which, further calls to run kill the block.

Maybe this is overkill? Perhaps just preventing two blocks from running at the same time is enough? Is there a usecase for creating a block and running it multiple times?

Add an API for centering text

center(WIDTH, string)

so center(10, "Hi") would generate (assume X's are spaces):

XXXXHiXXXX

and you could use it like textLine(center(WIDTH, "message"))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.