Spaces:
Running
Running
<!-- livebook:{"app_settings":{"access_type":"public","output_type":"rich","show_source":true,"slug":"rune-finder"},"file_entries":[{"name":"UnicodeData.txt","type":"url","url":"https://raw.githubusercontent.com/ramalho/rf/master/elixir/UnicodeData.txt"}]} --> | |
# Rune finder | |
```elixir | |
Mix.install([ | |
{:kino, "~> 0.12.3"} | |
]) | |
``` | |
## About this | |
```elixir | |
import Kino.Shorts | |
``` | |
````elixir | |
markdown(""" | |
<details> | |
<summary>About this app</summary> | |
Find Unicode characters by name. | |
For example, for `face cat` | |
``` | |
U+1F431 ๐ฑ CAT FACE | |
U+1F638 ๐ธ GRINNING CAT FACE WITH SMILING EYES | |
U+1F639 ๐น CAT FACE WITH TEARS OF JOY | |
U+1F63A ๐บ SMILING CAT FACE WITH OPEN MOUTH | |
U+1F63B ๐ป SMILING CAT FACE WITH HEART-SHAPED EYES | |
U+1F63C ๐ผ CAT FACE WITH WRY SMILE | |
U+1F63D ๐ฝ KISSING CAT FACE WITH CLOSED EYES | |
U+1F63E ๐พ POUTING CAT FACE | |
U+1F63F ๐ฟ CRYING CAT FACE | |
U+1F640 ๐ WEARY CAT FACE | |
``` | |
</details> | |
""") | |
```` | |
## Code | |
```elixir | |
content = | |
Kino.FS.file_path("UnicodeData.txt") | |
|> File.read!() | |
``` | |
```elixir | |
defmodule RuneFinder do | |
defp to_rune(code, name) do | |
rune = <<String.to_integer(code, 16)::utf8>> | |
"U+#{code}\t#{rune}\t#{name}" | |
end | |
defp select(line_stream, query_words) do | |
Enum.map(line_stream, fn line -> | |
[code, name | _] = String.split(line, ";") | |
if MapSet.subset?(query_words, tokenize(name)), do: to_rune(code, name) | |
end) | |
|> Enum.reject(&(&1 == nil)) | |
end | |
defp find(query_words) do | |
Kino.FS.file_path("UnicodeData.txt") | |
|> File.stream!() | |
|> select(query_words) | |
end | |
defp tokenize(text) do | |
text | |
|> String.replace("-", " ") | |
|> String.split() | |
|> MapSet.new() | |
end | |
def main(args) do | |
args | |
|> String.upcase() | |
|> tokenize | |
|> find | |
end | |
end | |
``` | |
```elixir | |
form = | |
Kino.Control.form( | |
[ | |
name: Kino.Input.text("Unicode characters name", default: "face cat") | |
], | |
submit: "Find" | |
) | |
``` | |
```elixir | |
output_frame = frame() | |
Kino.listen(form, fn event -> | |
origin = event.origin | |
Kino.Frame.clear(output_frame, to: origin) | |
case event.data.name do | |
"" -> | |
Kino.Frame.render(output_frame, "Please provide words to find.", to: origin) | |
_ -> | |
runes = RuneFinder.main(event.data.name) | |
Enum.each(runes, fn rune -> | |
Kino.Frame.append(output_frame, text(rune), to: origin) | |
end) | |
Kino.Frame.append(output_frame, text("\n#{Enum.count(runes)} found"), to: origin) | |
end | |
end) | |
output_frame | |
``` | |