Skip to content

Commit 1de6d7c

Browse files
committed
Initial commit
0 parents  commit 1de6d7c

File tree

9 files changed

+255
-0
lines changed

9 files changed

+255
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Manifest.toml
2+

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 GHTaarn
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Project.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name = "UnicodeREPL"
2+
uuid = "386912cb-a936-462a-a347-7bd6cef0b04e"
3+
authors = ["GHTaarn <[email protected]>"]
4+
version = "0.1.0"
5+
6+
[deps]
7+
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
8+
ReplMaker = "b873ce64-0db9-51f5-a568-4457d8e49576"
9+
10+
[compat]
11+
ReplMaker = "0.2.2"
12+
julia = "~1.0, ~1.1, ~1.2, ~1.3, ~1.4, ~1.5, ~1.6, ~1.7, ~1.8, ~1.9, ~1.10, ~1.11"

README.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# UnicodeREPL
2+
3+
This is a small [Julia](https://julialang.org) package that enables the user
4+
to obtain any Unicode character (that the system fonts can display) in the
5+
Julia REPL if the [Unicode codepoint](https://codepoints.net) is known.
6+
7+
## Installation
8+
9+
In the Julia REPL type:
10+
```julia
11+
import Pkg
12+
Pkg.add("https://github.com/GHTaarn/UnicodeREPL.jl")
13+
```
14+
15+
## Use
16+
17+
In the Julia REPL type:
18+
```julia
19+
using UnicodeREPL
20+
```
21+
22+
Hereafter, you will be able to enter "unicode repl" mode by typing
23+
the `^` character at the start of a line.
24+
In "unicode repl" mode, any pattern matching `\u(XXXX)` will be
25+
converted to the Unicode character corresponding to `XXXX`, where `XXXX` is a
26+
string of any length containing the hexadecimal
27+
[Unicode codepoint](https://codepoints.net) of a valid Unicode character.
28+
29+
Pressing the `Backspace` key when the cursor is on the first character of a
30+
"unicode repl" mode line reverts back to "julia" mode while preserving
31+
the contents of the input line.
32+
33+
"unicode repl" mode has most features that "julia" mode has.
34+
35+
### Examples
36+
```julia-repl
37+
julia> using UnicodeREPL
38+
REPL mode unicode_completion initialized. Press ^ to enter and backspace to exit.
39+
40+
unicode repl> println("\u(2560)\u(2563)ello World\u(266c)")
41+
╠╣ello World♬
42+
43+
unicode repl> println("╠\u(2563)ello World\u(266c)")
44+
╠╣ello World♬
45+
46+
unicode repl> println("╠╣ello World♬")
47+
╠╣ello World♬
48+
49+
unicode repl> println("20\u(0b0)C")
50+
20°C
51+
52+
unicode repl> println("20\u(B0)C")
53+
20°C
54+
55+
unicode repl> println("20°C")
56+
20°C
57+
58+
unicode repl>
59+
```
60+
61+
The first "unicode repl" line shows what happens when merely pressing
62+
`Enter` in this mode.
63+
64+
The second "unicode repl" line shows what would happen if the `Tab` key
65+
was pressed when the cursor was on the second `\` character of the first
66+
"unicode repl" line: The `Tab` key immediately substitutes to the left
67+
of the cursor. Hereafter `Enter` was pressed.
68+
69+
The third "unicode repl" line is what most people want: It was
70+
initially identical to the first "unicode repl" line, hereafter the
71+
`Tab` key was pressed when the cursor was at the end of the line followed by
72+
the `Enter` key.
73+
74+
The next two "unicode repl" lines show that leading zeros and both
75+
upper and lower case codepoints are allowed.
76+
77+
The final "unicode repl" line shows the effect of pressing the `Tab`
78+
key at the end of either of the previous two input lines.
79+
80+
Note that while any Unicode character can be entered in this way, characters
81+
such as `°` that can be handled in "julia" mode should normally be entered
82+
using [standard tab completion sequences](https://docs.julialang.org/en/v1/manual/unicode-input/)
83+
as this minimises the risk of confusion with similar looking characters.
84+
85+
## Feedback
86+
87+
This is a very rough first version, the plan is to make the user experience
88+
smoother in the future. If you encounter real bugs then please report them at
89+
https://github.com/GHTaarn/UnicodeREPL.jl/issues or submit a pull request.
90+
Ideas for extra Unicode related features are also welcome although of course
91+
I cannot necessarily promise to implement them.

src/UnicodeREPL.jl

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
"""
2+
# UnicodeREPL
3+
4+
On an empty line, press ^ to enter unicode_repl mode and backspace to exit.
5+
6+
In unicode_repl mode, `\\u(XXXX)` tab completes to the symbol at Unicode
7+
codepage `XXXX` where `XXXX` is a hexadecimal string of any length.
8+
9+
## Exported Symbols
10+
11+
[`ufind`](@ref)
12+
"""
13+
module UnicodeREPL
14+
15+
using ReplMaker
16+
import REPL
17+
import REPL.LineEdit.complete_line
18+
import REPL.LineEdit.CompletionProvider
19+
20+
export ufind
21+
22+
struct UnicodeCompletionProvider <: CompletionProvider
23+
repl_completion_provider::CompletionProvider
24+
end
25+
26+
function substitution(istr::AbstractString)
27+
substr = split(istr, "\\u(")
28+
if length(substr) == 1
29+
return istr
30+
else
31+
ostr = substr[1]
32+
for str in substr[2:end]
33+
m = match(r"^[0-9a-fA-F]+[)]", str)
34+
ostr *=
35+
if m == nothing
36+
"\\u(" * str
37+
else
38+
codepoint = m.match[1:end-1]
39+
Meta.parse("\"\\u$codepoint\"") * str[length(m.match)+1:end]
40+
end
41+
end
42+
return ostr
43+
end
44+
end
45+
46+
"""
47+
ufind(r::Union{AbstractString,Regex})
48+
49+
Return the Unicode completion pairs whose keys match `r`
50+
51+
## Example
52+
```julia-repl
53+
julia> using UnicodeREPL
54+
REPL mode unicode_repl initialized. Press ^ to enter and backspace to exit.
55+
56+
julia> ufind("feed")
57+
2-element Vector{Pair{String, String}}:
58+
"\\\\:breast-feeding:" => "🤱"
59+
"\\\\linefeed" => "↴"
60+
61+
julia> ufind(r"^[^:]*feed")
62+
1-element Vector{Pair{String, String}}:
63+
"\\\\linefeed" => "↴"
64+
65+
julia>
66+
```
67+
68+
Note that Unicode codepages themselves are not included, so the mapping
69+
`"\\\\u(feed)" => "ﻭ"` is not in the output.
70+
"""
71+
function ufind(r::Union{AbstractString,Regex})
72+
completions = vcat(collect(REPL.REPLCompletions.latex_symbols),
73+
collect(REPL.REPLCompletions.emoji_symbols))
74+
filter(pair->contains(pair.first,r), completions) |> sort
75+
end
76+
77+
function input_handler(inputstr)
78+
Main.eval(Meta.parse(substitution(inputstr)))
79+
end
80+
81+
function complete_line(x::UnicodeCompletionProvider, s::REPL.LineEdit.PromptState)
82+
firstpart = String(s.input_buffer.data[1:s.input_buffer.ptr-1])
83+
firstpartsub = substitution(firstpart)
84+
if firstpart != firstpartsub
85+
return ([firstpartsub], firstpart, true)
86+
elseif VERSION <= v"1.9-"
87+
return complete_line(x.repl_completion_provider, s)
88+
else
89+
return complete_line(x.repl_completion_provider, s, Main)
90+
end
91+
end
92+
93+
function __init__()
94+
if !isinteractive()
95+
@info "Session is not interactive"
96+
return
97+
end
98+
initrepl(input_handler;
99+
prompt_text="unicode repl> ",
100+
prompt_color=26,
101+
start_key='^',
102+
mode_name=:unicode_repl,
103+
completion_provider=UnicodeCompletionProvider(REPL.REPLCompletionProvider()))
104+
end
105+
106+
end # module

test/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[deps]
2+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

test/runtests.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
include("substitution.jl")
3+
include("ufind.jl")
4+

test/substitution.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using Test
2+
using UnicodeREPL
3+
4+
@testset "substitution" begin
5+
@test UnicodeREPL.substitution("\\u(2560)\\u(2563)ello World!") == "╠╣ello World!"
6+
@test UnicodeREPL.substitution("\\u(bed) \\u(cab) \\u(feed) \\u(dad) \\u(BEEF)") == "௭ ಫ ﻭ ත 뻯"
7+
end

test/ufind.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using Test
2+
using UnicodeREPL
3+
4+
@testset "ufind" begin
5+
@test ufind(r"^\\alpha$") == ["\\alpha" => "α"]
6+
@test ("\\div" => "÷") in ufind("div")
7+
@test "" values(ufind("feed"))
8+
@test "\ufeed" values(ufind("feed"))
9+
end
10+

0 commit comments

Comments
 (0)