Skip to content

Commit

Permalink
Prompt (#175)
Browse files Browse the repository at this point in the history
* prompt init

* small fixes to repr and error

* fixed small repr bugs

* removed deps

* wip errors

* bump

* bump

* bump

* bump

* prompt wip

* bump

* prompt almost finished

* added tests and docs for prompt

* bump

* coverage and CI
  • Loading branch information
FedeClaudi authored Dec 16, 2022
1 parent cf92b7c commit 143c9ba
Show file tree
Hide file tree
Showing 42 changed files with 521 additions and 45 deletions.
5 changes: 1 addition & 4 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Term"
uuid = "22787eb5-b846-44ae-b979-8e399b8463ab"
authors = ["FedeClaudi <federicoclaudi@protonmail.com> and contributors"]
version = "1.1.0"
version = "1.2.0"

[deps]
CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"
Expand All @@ -13,14 +13,12 @@ Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
MyterialColors = "1c23619d-4212-4747-83aa-717207fae70f"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
ProgressLogging = "33c8b6b6-d38a-422a-b730-caa89a2f386c"
SnoopPrecompile = "66db9d55-30c0-4569-8b51-7e840670fc0c"
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
UnicodeFun = "1cfade01-22cf-5700-b092-accc4b62d6e1"
WordTokenizers = "796a5d58-b03d-544a-977e-18100b691f6e"

[compat]
CodeTracking = "1"
Expand All @@ -32,7 +30,6 @@ ProgressLogging = "0.1"
SnoopPrecompile = "1"
Tables = "1"
UnicodeFun = "0.4"
WordTokenizers = "0.5"
julia = "1.6"

[extras]
Expand Down
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ makedocs(;
"basics/renderables.md",
"basics/tprint.md",
"basics/console.md",
"basics/prompt.md",
],
"Renderables" => Any[
"ren/intro.md",
Expand Down
4 changes: 2 additions & 2 deletions docs/src/adv/errors_tracebacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ install_term_stacktrace(
but you can also do more, if you just want to quickly change some options (e.g. to deal with a particularly though bug). You can set flags to change the behavior on the fly:

```@example
import Term: STACKTRACE_HIDE_MODULES, STACKTRACE_HIDE_FRAME
import Term: STACKTRACE_HIDE_MODULES, STACKTRACE_HIDE_FRAMES
STACKTRACE_HIDE_MODULES[] = ["REPL", "OhMyREPL"] # list names of modules you want ignored in the stacktrace
STACKTRACE_HIDE_FRAME[] = false # set to true to hide frame, false to show all of them
STACKTRACE_HIDE_FRAMES[] = false # set to true to hide frame, false to show all of them
```
14 changes: 14 additions & 0 deletions docs/src/api/api_prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Prompts
```@meta
CurrentModule = Term.Prompts
```


```@index
Pages = ["api_prompt.md"]
```


```@autodocs
Modules = [Prompts]
```
55 changes: 55 additions & 0 deletions docs/src/basics/prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Prompt

Time for a little example of a simple thing you can use `Term.jl` for: asking for some input. Use a `Prompt`, ask a question, get an answer. Simple, but a little extra style. That's what `AbstractPrompt` types are for. There's a few different flavors, which we'll look at in due time, but essentially a prompt is made of a bit of text, the `prompt` that is displayed to the user, and some machinery to capture the user's input and parse it/ validate it.

For example:

```@example prompt
using Term.Prompts
Prompt("Simple, right?") |> ask
```

here we construct a basic `Prompt` and "ask" it: print the message and capture the reply. `ask` returns the answer, which you can do with as you please. A small warning before we carry on:

!!! warning "Using VSCode"
As you can see [here](https://discourse.julialang.org/t/vscode-errors-with-user-input-readline/75097/4?u=fedeclaudi), `readlines`, which `AbstractPrompts` use to get the user's input, is a bit troublesome in VSCode. In VSCode, after the prompt gets printed you need to enter "space" (hit the space bar) and then enter and **after** that you can enter your actual replies.

## Prompt flavours
There's a couple more ways you can use prompts like. One is to ensure you get an answer of the correct `Type`, using the immaginatively names `TypePrompt`:

```@example prompt
# this only accepts `Int`s
TypePrompt(Int, "give me a number") |> ask
```

If your answer can't be converted to the correct type you'll get a `AnswerValidationError`, not good.


So, what if you want to get user inputs, but you don't want to handle any crazy input they can provide? Fear not, use `OptionsPrompt` so that only acceptable options will be ok. This will keep "asking" your prompt until the user's answer matches one of the given options

```@example prompt
OptionsPrompt(["a lot", "so much", "the most"], "How likely would you be to recomend Term.jl to a friend or colleague?") |> ask
```

Okay, so much typing though. Let's be realistic, most likely you just want to ask a yes/no question and the answer is likely just yes. So just use a `DefaultPrompt`:

```@example prompt
# one says the first option is the default
DefaultPropt(["yes", "no"], 1, "Confirm?") |> ask
```

still too much typing? Ask the user to `confirm`:

```@example prompt
confirm()
```

## Style
The style of prompt elements (e.g. the color of the prompt's text or of the options) is defined in `Theme`. You can also pass style information during prompt creation:

```@example prompt
Promt("Do you like this color?", "red") |> println
DefaultPropt(["yes", "no"], 1, "Confirm?", "green", "blue", "red")
9 changes: 8 additions & 1 deletion src/Term.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ module Term
using Unicode

const STACKTRACE_HIDDEN_MODULES = Ref(String[])
const STACKTRACE_HIDE_FRAME = Ref(true)
const STACKTRACE_HIDE_FRAMES = Ref(true)

const DEBUG_ON = Ref(false)

Expand Down Expand Up @@ -86,6 +86,7 @@ include("repr.jl")
include("compositors.jl")
include("grid.jl")
include("introspection.jl")
include("prompt.jl")

export RenderableText, Panel, TextBox, @nested_panels
export TERM_THEME, highlight
Expand Down Expand Up @@ -176,6 +177,12 @@ using .Repr: @with_repr, termshow, install_term_repr, @showme

using .Grid

using .Prompts

# ---------------------------------------------------------------------------- #
# PRE COMPILATION #
# ---------------------------------------------------------------------------- #

using SnoopPrecompile

@precompile_setup begin
Expand Down
27 changes: 21 additions & 6 deletions src/_errors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import Term: read_file_lines
function get_frame_file(frame::StackFrame)
file = string(frame.file)
file = Base.fixup_stdlib_path(file)
Base.stacktrace_expand_basepaths() && (file = something(Base.find_source_file(file), file))
Base.stacktrace_expand_basepaths() &&
(file = something(Base.find_source_file(file), file))
Base.stacktrace_contract_userdir() && (file = Base.contractuser(file))

return if isnothing(file)
Expand Down Expand Up @@ -127,7 +128,6 @@ function get_frame_function_name(frame::StackFrame, ctx::StacktraceContext)
(func = parse_kw_func_name(frame))
catch
end


# format function name
func = replace(
Expand All @@ -137,11 +137,15 @@ function get_frame_function_name(frame::StackFrame, ctx::StacktraceContext)
),
)

func = highlight(func) |> apply_style
func = replace(func, RECURSIVE_OPEN_TAG_REGEX => "")
try
func = replace(func, RECURSIVE_OPEN_TAG_REGEX => "")
catch
end

# reshape but taking care of potential curly bracktes
func = highlight(func) |> apply_style
func = reshape_text(func, ctx.func_name_w; ignore_markup = true)

return RenderableText(func)
end

Expand Down Expand Up @@ -385,7 +389,7 @@ function render_backtrace(
to_skip =
should_skip(frame, hide_frames, curr_module) &&
num [1, length(bt)] &&
STACKTRACE_HIDE_FRAME[]
STACKTRACE_HIDE_FRAMES[]

# keep track of frames being skipped
if num [1, length(bt)]
Expand All @@ -403,7 +407,7 @@ function render_backtrace(

else
# show number of frames skipped
if (to_skip == false || num == length(bt) - 1) && n_skipped > 0
if to_skip == false && n_skipped > 0
add_number_frames_skipped!(
content,
ctx,
Expand All @@ -426,6 +430,17 @@ function render_backtrace(
end
end
else
if num == length(bt) && n_skipped > 0
add_number_frames_skipped!(
content,
ctx,
to_skip,
num,
bt,
n_skipped,
skipped_frames_modules,
)
end
tot_frames_added += 1
end

Expand Down
6 changes: 5 additions & 1 deletion src/_repr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,11 @@ function style_function_methods(fun, methods::String; max_n = 11, width = defaul
)
end
methods_contents = if N > 1
methods_texts = RenderableText.(escape_brackets.(apply_style.(highlight.(_methods))); width = width - 20)
methods_texts =
RenderableText.(
escape_brackets.(apply_style.(highlight.(_methods)));
width = width - 20,
)
join(string.(map(i -> counts[i] * methods_texts[i], 1:length(counts))), '\n')
else
fun |> methods |> string |> split_lines |> first
Expand Down
18 changes: 12 additions & 6 deletions src/errors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Term:
do_by_line,
RECURSIVE_OPEN_TAG_REGEX,
STACKTRACE_HIDDEN_MODULES,
STACKTRACE_HIDE_FRAME
STACKTRACE_HIDE_FRAMES

import ..Links: Link
import ..Style: apply_style
Expand Down Expand Up @@ -97,8 +97,9 @@ function install_term_stacktrace(;
hide_frames = true,
)
@eval begin
function Base.showerror(io::IO, er, bt::Vector; backtrace = true)
function Base.showerror(io::IO, er, bt; backtrace = true)
print("\n")
# @info "Showing" er bt

# shorten very long backtraces
isa(er, StackOverflowError) && (bt = [bt[1:25]..., bt[(end - 25):end]...])
Expand Down Expand Up @@ -139,10 +140,14 @@ function install_term_stacktrace(;
end

# print message panel if VSCode is not handling that through a second call to this fn
isa(io.io, Base.TTY) &&
isa(io.io, Base.TTY) && begin
msg = highlight(error_message(er)) |> apply_style
msg = replace(msg, RECURSIVE_OPEN_TAG_REGEX => "")
msg = reshape_text(msg, ctx.module_line_w; ignore_markup = true)

Panel(
RenderableText(
highlight(error_message(er));
escape_brackets(apply_style(highlight(error_message(er))));
width = ctx.module_line_w,
);
width = ctx.out_w,
Expand All @@ -152,17 +157,18 @@ function install_term_stacktrace(;
title_justify = :center,
fit = false,
) |> print
end

catch cought_err # catch when something goes wrong during error handling in Term
@error "Term.jl: error while rendering error message: " cought_err

for (i, (exc, _bt)) in enumerate(current_exceptions())
i == 1 && println("Error during term's stacktrace generation:")
Base.show_backtrace(io, _bt)
print(io, '\n'^3)
Base.showerror(io, exc)
end

print(io, '\n'^5)
println(io, "Original error:")
Base.show_backtrace(io, bt)
Expand Down
Loading

0 comments on commit 143c9ba

Please sign in to comment.