<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>danigm.net - content</title><link>https://danigm.net/</link><description></description><lastBuildDate>Sat, 22 Jan 2022 00:00:00 +0100</lastBuildDate><item><title>Twitch: GNOME live coding streaming</title><link>https://danigm.net/twitch.html</link><description>&lt;p&gt;This year I've started with something that I wanted to do since the first COVID
lockdown, but never did. So as a first year resolution I decided to start
streaming and I created my Twitch channel &lt;a href="https://www.twitch.tv/abentogil"&gt;Abentogil&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/twitch-loop.png" /&gt;
&lt;/p&gt;

&lt;p&gt;I've been thinking about streaming since lockdown, when a group of Spanish
people created a nice initiative to teach kids how to code and other tech
stuff. I never participated on that initiative, but it was the seed of this.&lt;/p&gt;
&lt;p&gt;This year I've seen other GNOME streamers doing live coding, like &lt;a href="https://twitch.tv/ebassi"&gt;ebassi&lt;/a&gt;
and &lt;a href="https://www.youtube.com/c/GeorgesStavracas"&gt;Georges&lt;/a&gt; and, at the end, I pluck up the courage to start.&lt;/p&gt;
&lt;h2&gt;The plan&lt;/h2&gt;
&lt;p&gt;I've started with one our at the end of my day, so I'm trying to stream from
Monday to Thursday from 20:00 to 21:00 (CET).&lt;/p&gt;
&lt;p&gt;This routing also will help me to spend more time in free software development
regularly, so not just on weekends or holidays, but a bit of work everyday.&lt;/p&gt;
&lt;p&gt;Right now I've started working on my own projects, like &lt;a href="https://gitlab.gnome.org/danigm/timetrack/"&gt;Timetrack&lt;/a&gt; and
&lt;a href="https://gitlab.gnome.org/danigm/loop/"&gt;Loop&lt;/a&gt;. I've fixed some issues that I had with Gtk4 in Timetrack and I've
started to work on the Loop app to add a MIDI keyboard.&lt;/p&gt;
&lt;p&gt;The other day I discovered the &lt;a href="https://gitlab.gnome.org/bertob/app-ideas/-/issues/58"&gt;Music Grid&lt;/a&gt; app idea in the gitlab and it's
related with the MIDI implementation I've been working on, so the next thing
that I'll do on my streams is to create this music grid widget and add it to
the Loop app, to have a nice Music creation App.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/music-grid.png" /&gt;
&lt;/p&gt;

&lt;h2&gt;The language: Live coding in Spanish&lt;/h2&gt;
&lt;p&gt;I've decided to do the streaming mainly in Spanish. The main reason to do that
is because now you can find documentation and a lot of videos in English, but
for people that doesn't master the English language, it's harder to follow this
content and even harder to participate, to ask or say something.&lt;/p&gt;
&lt;p&gt;Spanish is also my main language, and the idea is not just create tutorials or
something like that, this is just for fun, and if I'm able to create a small
community or influence someone, I want to show that the language is not a
unbreakable barrier.&lt;/p&gt;
&lt;p&gt;I want to make this for the Spanish community, but that doesn't mean that for
some streams I cannot talk in English, all depends on the audience, of course,
if a non Spanish speaker comes and ask something, I'll answer in English and
try to do multilingual stream.&lt;/p&gt;
&lt;p&gt;The International English is the language to use in Free Software, but it's
really important to do not convert that in a barrier, because there are a lot
of different communities and people that don't know the language and the first
contact with something new is always better in your main language. Everything
is easier with help from people that's near to your cultural background.&lt;/p&gt;
&lt;h2&gt;The future&lt;/h2&gt;
&lt;p&gt;Right now I'm working on Loop and every stream is similar, live coding on this
Gtk4 music APP, but in the future I'll do different streams, doing different
things on each week day. These are the current ideas that could be a day on my
stream:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maintenance day: Work on my apps, code review, fixes, releases, and
   development.&lt;/li&gt;
&lt;li&gt;GNOME Love day: Give some love to the GNOME project, look for simple bugs to
   solve in different projects, help with translations, initiatives, and other
   possible one hour task to give some love to the project in general.&lt;/li&gt;
&lt;li&gt;Learning day: Pick some technology and learn by doing, for example, I
   can explore new programming languages writing a simple app, learn about
   Linux writing a driver, learn how to animate with blender, anything new to
   play and discover.&lt;/li&gt;
&lt;li&gt;Newcomers day: Create simple tutorial or introduction to some technology,
   How to write a GNOME Shell extension, how to create a Gtk4 app in python,
   teach to code from zero, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is just a list of ideas, if I discover any other interesting use of this
time and stream, I can do that. The final goal of this is to have fun, and if
someone learns something in the journey, that's even better.&lt;/p&gt;
&lt;p&gt;I'll also upload any interesting stream to &lt;a href="https://www.youtube.com/danigmx"&gt;youtube&lt;/a&gt;, so the good content
could be viewed on demand.&lt;/p&gt;
&lt;p&gt;So if you like this, don't hesitate to view some of the streams and say "Hola":&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;a href="https://twitch.tv/abentogil"&gt;
        &lt;img src="/pictures/twitch.jpg" /&gt;
    &lt;/a&gt;
&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 22 Jan 2022 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2022-01-22:/twitch.html</guid><category>content</category><category>gnome</category><category>software</category><category>outreach</category><category>twitch</category><category>live coding</category></item><item><title>Loop: A simple music application</title><link>https://danigm.net/loop.html</link><description>&lt;p&gt;In the last year I've seen some &lt;a href="https://www.twitch.tv/leonbratt"&gt;really good musician&lt;/a&gt; that performs all
the instruments in a song with just a loop machine, recording each instrument
one by one in tracks and looping.&lt;/p&gt;
&lt;p&gt;I was thinking that it should be easy to have a desktop application that does
exactly the same, just some tracks to record some sounds and the playback with
a loop option, and that's what I created during this week.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/loop.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://gitlab.gnome.org/danigm/loop/"&gt;Loop application&lt;/a&gt; is just a simple Gtk4 application that uses gstreamer
to record tracks and then you can play each one at the same with or without
loop option. With that, a good musician could create the base melody of the
song and then sign on top of that. Unfortunately, I'm not a good musician, but
I can use this to play around.&lt;/p&gt;
&lt;p&gt;I've just created the &lt;a href="https://github.com/flathub/flathub/pull/2674"&gt;request on flathub&lt;/a&gt; to add the application, so if
everything is okay it will be available there soon, so more people can play
with this awesome toy.&lt;/p&gt;
&lt;p&gt;Right now it has the basic record, play and loop functionality with just four
tracks, so don't expect to have a professional music app (yet). The recording
and play times are not perfect and there's a delay, that's a known issue, but
I'm planning to fix this issue and add more functionality in the future, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make number of tracks configurable&lt;/li&gt;
&lt;li&gt;Import track from files&lt;/li&gt;
&lt;li&gt;Add a trim slider per track, to be able to adjust the recorder track to loop&lt;/li&gt;
&lt;li&gt;Metronome tick and clock to have a visual reference for recording tracks&lt;/li&gt;
&lt;li&gt;A record button, but export the combination of all tracks and mic to a mp3
   file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that's all. The logo and design is an initial version done by myself, so if
any designer wants to take a look, all contributions are welcome. And of course
any code contribution is also welcome.&lt;/p&gt;
&lt;p&gt;If you use this application and do some good or fun performance, please, ping
me on social networks and let me know.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 11 Dec 2021 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2021-12-11:/loop.html</guid><category>content</category><category>gnome</category><category>software</category><category>music</category><category>loop</category></item><item><title>Endless Orange Week: Hack content creators platform (2)</title><link>https://danigm.net/hack-content-creators-1.html</link><description>&lt;p&gt;The past Friday was the last day of the &lt;a href="http://danigm.net/hack-content-creators.html"&gt;Endless Orange Week&lt;/a&gt;. It was a nice
and fun experience, and even if I was not able to do as much as I wanted, we
were able to make something that "works" in the Hack project.&lt;/p&gt;
&lt;h2&gt;The Hack Quest editor&lt;/h2&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/clubhouse-custom-quests-1.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The first step to have custom quests on the Hack app was to complete the
&lt;a href="https://www.inklestudios.com/ink/"&gt;Ink language&lt;/a&gt; support. We started to work on this some time ago, but never
completed the functionality.&lt;/p&gt;
&lt;p&gt;I worked on that the first three days, updating the ink library and building
the missing pieces to be able to load quests from random paths. I've
implemented that in a way that the Hack application is able to receive a path
to a &lt;code&gt;.ink&lt;/code&gt; file, and it's able to build and run the quets.&lt;/p&gt;
&lt;p&gt;The Quests are not just the script, but they have some metadata, like title,
subtitle, description, difficulty and the card image to show on the interface.
To solve that I defined a "custom quest bundle format", that's bassically a
folder with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;questId&lt;/li&gt;
&lt;li&gt;quest.jpg&lt;/li&gt;
&lt;li&gt;metadata.json&lt;/li&gt;
&lt;li&gt;quest.ink&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I also added the functionality to import a bundle zip file and export with
the quest information.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/clubhouse-custom-quests-2.png" /&gt;
&lt;/p&gt;

&lt;p&gt;I created some command line options to use this new functionality:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ink&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FULL_INK_FILE_PATH&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;import&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PATH_TO_BUNDLE_OR_INK_FILE&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;Import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CUSTOM_QUEST_ID&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Quest creation interface and the Inky Editor&lt;/h3&gt;
&lt;p&gt;The first idea was to try to provide a full quest creation experience in the
app, but that was too much, so we decided to simplify the way to create quests
and depend on the &lt;a href="https://flathub.org/apps/details/com.inklestudios.Inky"&gt;Inky editor&lt;/a&gt; external tool. Manuel Quiñones took some time
to update the flatpak application with the latests ink version, so we can use
to create custom quests.&lt;/p&gt;
&lt;p&gt;The Inky editor provides help about the language, syntax highlighting and a
simple way to test the script, so it's a nice tool. The main problem with this
tool is that it doesn't provide a way to launch it with a file path so it's
not possible to integrate with the Hack app.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/clubhouse-custom-quests-3.png" /&gt;
&lt;/p&gt;

&lt;p&gt;So at the end, the Quest creation dialog is just a way to define the metadata
and to select the Quest ink files from your filesystem. How the ink script is
created is a decision to make for the content creator.&lt;/p&gt;
&lt;h3&gt;The future&lt;/h3&gt;
&lt;p&gt;We've no time to complete all we wanted to do, and I didn't create a new
release, so this new functionality is still not there. But we'll try to do a
release soon.&lt;/p&gt;
&lt;p&gt;Simon is working on some interface improvements and also on a new tutorial
Quest, so we can introduce the Custom Quest creation tool in the same app.&lt;/p&gt;
&lt;h2&gt;The Character editor&lt;/h2&gt;
&lt;p&gt;The other part of this week planning was the character editor. Joana did a
really nice work designing the application, the initial assets and the user
experience, but I had not too much time to work on the implementation.  So I
spent just one day working on this.&lt;/p&gt;
&lt;p&gt;The main idea was to create a new independent app, and then provide a way to
integrate with the Hack application and the custom Quest creation dialog. And
it'll be a simple application so maybe it could be useful or interesting for
other people, it's a fun way to play around and create random faces.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/avatar-creator-1.png" /&gt;
&lt;/p&gt;

&lt;p&gt;We just created the application &lt;a href="https://github.com/endlessm/avatar-creator/"&gt;Avatar Creator&lt;/a&gt;. I created a simple python
Gtk4 application and worked a bit on the basic functionality. So right now it
loads a list of svg assets and provide the 3x3 grid. You can click on a grid
cell and then choose what basic image should go there.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/avatar-creator-2.png" /&gt;
&lt;/p&gt;

&lt;p&gt;I added the initial set of basic images, created by Joana, to create this funny
robot faces, but the format is simple enough to extend with different "avatar
libraries" in the future.&lt;/p&gt;
&lt;p&gt;Right now it's also possible to export to png, so the app is functional, but it
needs a bit more work.&lt;/p&gt;
&lt;p&gt;My idea is to work a bit more in the following weeks, when I have some time, on
weekends or holidays and at some point, publish it in flathub. And lets see if
there are more developers interested on this app so it can grow.&lt;/p&gt;
&lt;p&gt;The application is simple enough to be a good place for GNOME newcomers and it's
also a fun project to work on. A simple toy app to create faces that could
have some potential, some future ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"Smart" random faces generator&lt;/li&gt;
&lt;li&gt;Configurable grid: Maybe is interesting to make it bigger or smaller to play
   around&lt;/li&gt;
&lt;li&gt;Programmed simple base image manipulations, like rotation, mirror, color&lt;/li&gt;
&lt;li&gt;Animation creation, maybe be able to export to gif&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Endless Orange Week experience&lt;/h2&gt;
&lt;p&gt;This week was a really nice experience, because we were working in a "personal"
chosen project, that we liked and without the day to day meetings, times
schedules and other related work stuff.&lt;/p&gt;
&lt;p&gt;But that was not all. In Endless we've different teams that work mostly
isolated, because we're working on different fields, we've some overlapping,
but we work day to day as small teams, and this week we were all using the same
slack channel to show our progress, and it was nice.&lt;/p&gt;
&lt;p&gt;Maybe now that we're not a big organization with a lot of workers, we can do
something like this more often, it's always good to know more about other
coworkers and to learn something that maybe it's not related with your main
project, but it could be interesting.&lt;/p&gt;
&lt;p&gt;I'm really happy that we did this Endless Orange Week, it's sad that it ended
too soon, I'm waiting to learn from my coworkers what amazing things they do
during this week and I'm looking forward the next year Orange Week!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Mon, 15 Nov 2021 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2021-11-15:/hack-content-creators-1.html</guid><category>content</category><category>hack</category><category>endless</category><category>orangeweek</category><category>work</category><category>gnome</category><category>software</category></item><item><title>Endless Orange Week: Hack content creators platform</title><link>https://danigm.net/hack-content-creators.html</link><description>&lt;p&gt;This week (Nov 8 – 12) I am participating in Endless Orange Week, a program
where the entire &lt;a href="https://www.endlessos.org/"&gt;Endless&lt;/a&gt; team engages in projects designed to grow our
collective learning related to our skills, work and mission.&lt;/p&gt;
&lt;p&gt;We propose a project, that could be anything, and then work during the whole
week, without distraction. I've choosed to work on the &lt;a href="https://www.hack-computer.com/"&gt;Hack project&lt;/a&gt;, that's a
really nice project that needs some love, because since the past year, we have
&lt;a href="https://www.endlessos.org/key"&gt;other priorities&lt;/a&gt;, so there's no time to improve the Hack app.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;a href="/pictures/clubhouse.png"&gt;
        &lt;img src="/pictures/clubhouse.png" /&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;The project: Hack content creators platform&lt;/h2&gt;
&lt;p&gt;The Hack application is a "Quest" launcher, and each Quest is an interactive
learning experience, a guided introduction to some technology or topic.&lt;/p&gt;
&lt;p&gt;Quests are just python scripts, with a simple library to expose messages to the
user, ask questions, or wait for desktop events, like launch an application,
focus an application, etc. And all these Quests are inside the application, and
are created by the Hack team and released with a new Hack app flatpak.&lt;/p&gt;
&lt;p&gt;The main idea of the project is to provide a simple Quest editor to allow any
Hack user to create and share their our Quests.&lt;/p&gt;
&lt;p&gt;To have this Hack content creators platform we'll need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To simplify the way we create Quests, instead of a python script, we'll uses
   a Domain Specific Language, called &lt;a href="https://www.inklestudios.com/ink/"&gt;Ink&lt;/a&gt;. We started to work on this, but
   we never ended the support.&lt;/li&gt;
&lt;li&gt;To create the interface to be able to import and export custom Quests, that
   could be zip bundles, with the Ink script and some images.&lt;/li&gt;
&lt;li&gt;To create the interface to write the actual Quests and save or bundle.&lt;/li&gt;
&lt;li&gt;Create some introductory Quest to explain "how to create your own Quests!".&lt;/li&gt;
&lt;li&gt;Create an character editor, to be able to "design" new characters for Quests.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;The Quest editor&lt;/h3&gt;
&lt;p&gt;The Quests will be written using the Ink language, and there's &lt;a href="https://flathub.org/apps/details/com.inklestudios.Inky"&gt;something done before&lt;/a&gt;.
The first idea is to just provide a text editor and some helpful information
about the format, and maybe a button to validate. But if there's time we can
use something advanced or even integrate the &lt;a href="https://flathub.org/apps/details/com.inklestudios.Inky"&gt;Inky&lt;/a&gt; editor.&lt;/p&gt;
&lt;h3&gt;The Character editor&lt;/h3&gt;
&lt;p&gt;Each Quest has a main character, and we've five in the Hack app right now, but
it could be great to be able to define new ones for custom Quests. That's the
idea of this part of the project.&lt;/p&gt;
&lt;p&gt;The initial idea is to have a library of character parts to combine, and the
editor will allow the user to combine this parts and maybe change colors, to be
able to create unique characters for your Quests.&lt;/p&gt;
&lt;h3&gt;The Team&lt;/h3&gt;
&lt;p&gt;I'm not working alone in this "side" project during the Endless Orange Week,
Simon Schampijer and Joana Filizola will be working on this too, so this is a
big task but we've a great team. Let's see how far we are able to go during
just one week.&lt;/p&gt;
&lt;h3&gt;The impact&lt;/h3&gt;
&lt;p&gt;This is just a project to try to keep alive more time the Hack application,
without a lot of effort or a whole team behind it. We are not able to put more
content there periodically, so if there's a way to create new content easily
and (maybe in the future) a way to publish, it'll be possible to create a
community around the project.&lt;/p&gt;
&lt;p&gt;And we have also new possibilities, in the near future, we can add some Hack
content to the Endless Key, and using the Ink language, so this editor could
help to bring more content there easily.&lt;/p&gt;
&lt;p&gt;And the final piece, the Character editor, could be an independent application,
a nice simple application that could be used to create your character for your
profile photo, or to generate random character pics.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Mon, 08 Nov 2021 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2021-11-08:/hack-content-creators.html</guid><category>content</category><category>hack</category><category>endless</category><category>orangeweek</category><category>work</category><category>gnome</category><category>software</category></item><item><title>Fractal: Refactoring and the review process</title><link>https://danigm.net/gsoc-2020-1.html</link><description>&lt;p&gt;In this year GSoC, &lt;a href="https://aledomu.github.io/gnome/refactoring-fractal-remove-backend-i/"&gt;Alejandro&lt;/a&gt; is working on Fractal, moving code from the
backend to the client, to try to simplify the code used to communicate with the
matrix.org server and maybe in the future we can replace &lt;code&gt;fractal-matrix-api&lt;/code&gt;
with the &lt;a href="https://matrix.org/sdks/#matrix-rust-sdk"&gt;matrix-rust-sdk&lt;/a&gt;. And then we'll have less code in our project to
maintain.&lt;/p&gt;
&lt;p&gt;This is a great work, something needed in a project with a technological debt
of several years. I created this project to learn Rust, and also I was learning
about the matrix protocol during the project build. And other contributors do
the same. So we've been building one thing on top another for a lot of years.&lt;/p&gt;
&lt;p&gt;In this kind of community driven projects it's the way to go. For some time
we've people interested and developers think about the design and start change
some parts or to write new functionality following a new design pattern. But
voluntary developers motivation change in time and they left the project and
the next one continues the work with a different vision.&lt;/p&gt;
&lt;p&gt;It's not something bad, it's the greatness of the open source. Different people
has different motivations to participate in a free software project, and every
contribution is welcome. I'm the maintainer of the project and I've spent a lot
of time building Fractal, but I don't have the same motivation now to work on
the project, to it's good to have other people working on it so it can continue
alive.&lt;/p&gt;
&lt;p&gt;Alejandro is doing a great work and he's not a 4 months contributor. He's
working on the backend refactoring for 2 years now, step by step and he has
plans for the future.&lt;/p&gt;
&lt;p&gt;Refactoring a big project is always hard, because there's a lot of code
movement and always there's the fear to regressions.&lt;/p&gt;
&lt;p&gt;Rust is a great language and it shines when big code refactoring comes to the
scene. If it compiles, you &lt;strong&gt;know&lt;/strong&gt; that there's no memory errors, dangling
pointers and that kind of problems. If it builds it will work.&lt;/p&gt;
&lt;p&gt;But maybe it will work &lt;em&gt;different&lt;/em&gt;, so the review process is needed to ensure
that the application continues working.&lt;/p&gt;
&lt;p&gt;Automated tests are really useful for big code changes and project refactoring,
because you have a quick picture and some certainty that the project is
working. But we don't have tests in fractal :D, so someone should do that.&lt;/p&gt;
&lt;p&gt;So here I am. &lt;a href="https://gitlab.gnome.org/GNOME/fractal/-/merge_requests/581"&gt;Reviewing large MR&lt;/a&gt;, with a lot of lines. At least gitlab
makes this process a bit easier.&lt;/p&gt;
&lt;p&gt;What I'm trying to do in the review process is to just read the whole diff and
check if there's some problem in the code. And after every change, I run the
app and I do some tests, trying to use the functionality that could be broken
by those new changes.&lt;/p&gt;
&lt;p&gt;This takes a lot of time and it's not something fun to do... But someone has to
do that. And during that process, sometimes I learn something new. Reading code
is an interesting task and try to find bugs in code while reading it, is
something useful. To think about that code, what it does and why.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Tue, 30 Jun 2020 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2020-06-30:/gsoc-2020-1.html</guid><category>content</category><category>gnome</category><category>software</category><category>fractal</category><category>gsoc</category></item><item><title>Fractal: Google Summer of Code 2020</title><link>https://danigm.net/gsoc-2020.html</link><description>&lt;p&gt;I'm glad to say that I'll participate again in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;GSoC&lt;/a&gt;, as mentor. This
summer we'll try to implement multi-account support in &lt;a href="https://gitlab.gnome.org/GNOME/fractal"&gt;Fractal&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/fractal-gsoc.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The selected student is &lt;a href="https://summerofcode.withgoogle.com/projects/#6726209787920384"&gt;Alejandro Dominguez&lt;/a&gt; (aledomu), that is
collaborating with Fractal since the Seville Hackfest in December 2018, doing
a great work in the backend. Alejandro is young developer with a lot of energy
and ideas, so it's great to have this kind of people working on GNOME.&lt;/p&gt;
&lt;p&gt;I've not spend much time lately developing Fractal, the time and energy is
limited, but I'll try to use this GSoC mentorship to go back to the &lt;strong&gt;active&lt;/strong&gt;
Fractal development. My objective during this summer will be to stabilize,
fix bugs and improve the performance and create a new release at the end of the
GSoC, because we've a lot of new functionality in master, but I didn't spend
the time to do the release.&lt;/p&gt;
&lt;p&gt;The google summer of code is a great opportunity for free software, it give
us a full time working student, during three months, working on free software,
so it's really appreciated in a community where a lot of work is volunteer work.&lt;/p&gt;
&lt;p&gt;There are a total of 14 projects selected for this GSoC round for gnome, you
can take a look to the full list in the &lt;a href="https://summerofcode.withgoogle.com/organizations/5428225724907520/#projects"&gt;GSoC page&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Fri, 08 May 2020 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2020-05-08:/gsoc-2020.html</guid><category>content</category><category>gnome</category><category>software</category><category>fractal</category><category>gsoc</category></item><item><title>Andaluh-rs, a lib to transcript Spanish to Andaluh</title><link>https://danigm.net/andaluh.html</link><description>&lt;p&gt;Spain is a big region with a lot of languages, we've the official one for
the whole region, Spanish or Castilian (es-ES), and other officials languages
spoken in other regions, like the Galician (gl-ES) spoken in Galicia,
the Basque (eu-ES), spoken in the Basque Country, the Catalan (ca-ES)
spoken in Catalonia.&lt;/p&gt;
&lt;p&gt;But we've more languages that doesn't have the same official support, the
Valencian, the Aragonese, the Asturian, &lt;a href="https://en.wikipedia.org/wiki/Languages_of_Spain"&gt;and more&lt;/a&gt;. And also we've some
&lt;strong&gt;dialects&lt;/strong&gt; like the &lt;em&gt;Andalusian&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;All of this languages was discredit during the dictatorship period when the
only official language was the Spanish and the others was treated like
vulgar languages or non educated one, and in some cases the language was
&lt;em&gt;prohibited&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Whe the &lt;em&gt;democracy&lt;/em&gt; arrives, some regions spend a lot of resources trying to
recover the language and are supporting it until now with official institutions
and lessons in the official education system. But in other regions the stigma
continued until today.&lt;/p&gt;
&lt;p&gt;That's the case of the &lt;em&gt;Andalusian&lt;/em&gt;, that right now is not considered a language
but a dialect. In any case, this &lt;em&gt;dialect&lt;/em&gt; is treated as a non cultivated
language, spoken by illiterates. We've a lot of Spanish movies and Series where
the character that spoke &lt;em&gt;Andalusian&lt;/em&gt; was the illiterate, from the countryside
or the servant of the family.&lt;/p&gt;
&lt;h2&gt;Be proud of it&lt;/h2&gt;
&lt;p&gt;In Andalusia we've a lot of culture, literature and music done in &lt;em&gt;Andalusian&lt;/em&gt;,
but we don't have a way to write that and many people try to avoid the &lt;em&gt;acent&lt;/em&gt;
and the local words to look more cultured and because there's no a writing
system, we write in Spanish, it's hard to write lyrics, poetry and other
kind of literature. The Andalusian is not only a way to talk, some words are
short and we've contractions and other vowel sounds so if you write in Spanish,
it's not the same as spoken, some information is missed and for example in music
or poetry the metric doesn't match.&lt;/p&gt;
&lt;p&gt;There's a &lt;a href="https://andaluh.es/"&gt;movement&lt;/a&gt; trying to define a writing &lt;strong&gt;Andalusian&lt;/strong&gt; and promoting the
language, trying to make people proud of it and talk and write without complexes.&lt;/p&gt;
&lt;h2&gt;Translator, here comes the code&lt;/h2&gt;
&lt;p&gt;And there's a &lt;a href="https://github.com/andalugeeks/"&gt;group of developers&lt;/a&gt; that are working in some tools to provide
direct translation from Spanish and other tools to ease the &lt;strong&gt;Andalusian&lt;/strong&gt; writing.&lt;/p&gt;
&lt;p&gt;I like to write code and I'm always happy to find new problems to solve, to learn
new languages, tools and to spend some time trying to code something that I've not
done before. So I decided to write a translator from Spanish to Andaluh using rust,
and I've created the &lt;a href="https://github.com/andalugeeks/andaluh-rs"&gt;andaluh-rs&lt;/a&gt; lib.&lt;/p&gt;
&lt;p&gt;The translator is more or less easy, there're some rules that should be applied
from top to bottom that basically replaces some group of letters. There's a
implementation in &lt;a href="https://github.com/andalugeeks/andaluh-py"&gt;python&lt;/a&gt; that uses regular expressions for that. There're
a lot of regular expressions, so I thougth that it could be easy to use a parser,
so I used the &lt;a href="https://github.com/pest-parser/pest"&gt;pest parser&lt;/a&gt;.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;// supress muted /h/

H = { (&amp;quot;h&amp;quot; | &amp;quot;H&amp;quot;) }
initial_h = { H ~ letter }
CH = { C ~ H }
inner_ch = { CH ~ letter }
inner_h = { !inner_ch ~ H ~ letter }
hua = { H ~ (&amp;quot;ua&amp;quot; | &amp;quot;UA&amp;quot; | &amp;quot;Ua&amp;quot; | &amp;quot;uA&amp;quot;) }
hue = { H ~ (&amp;quot;ue&amp;quot; | &amp;quot;UE&amp;quot; | &amp;quot;Ue&amp;quot; | &amp;quot;uE&amp;quot;) }
noh = { !CH ~ !H ~ letter }
h = _{ ((sp|SOI)? ~ initial_h* ~ ((hua | hue | inner_ch | inner_h) | noh+)+)+ }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I've defined each rule in the pest format, so I've a parser for each rule
and then I can replace the word with the correct replacement.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;h_rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;: &lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;::&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;defs&lt;/span&gt;::&lt;span class="n"&gt;H_RULES_EXCEPT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;::&lt;span class="n"&gt;initial_h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;::&lt;span class="n"&gt;inner_h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;: &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;keep_case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;::&lt;span class="n"&gt;hue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;: &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;keep_case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;güe&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;::&lt;span class="n"&gt;hua&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;: &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;keep_case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;gua&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To simplify the code, I've defined the &lt;code&gt;rule&lt;/code&gt; macro, with the code used in
all rules:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$rule&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($t&lt;/span&gt;: &lt;span class="nc"&gt;pat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$r&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;: &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$rule&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$map&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($t&lt;/span&gt;: &lt;span class="nc"&gt;pat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$r&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;replace_exceptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="fm"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AndaluhParser&lt;/span&gt;::&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;: &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_rule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="cp"&gt;$(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="cp"&gt;$r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;::&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_some&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;replace_exceptions_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And because the Spanish and the Andaluh languages uses unicode and rust Strings
can not be iterated by &lt;em&gt;unicode&lt;/em&gt;, I've used &lt;code&gt;unicode_segmentation&lt;/code&gt; crate, and
defined some utility macros to get the real String len and to get slices of that
String.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;UnicodeSegmentation&lt;/span&gt;::&lt;span class="n"&gt;graphemes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$end&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;::&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;::&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;: &lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With all this done, we only have to apply all rules, in the correct order,
to the input string so we can get the translated String as output.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;epa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;: &lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// TODO: escape links&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;h_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;x_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ch_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;gj_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;v_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ll_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;l_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;psico_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;vaf_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;word_ending_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;digraph_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;exception_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;word_interaction_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;This code is not the best one, I'm doing a lot of string operations with copies
and clones, I'm sure that anyone with more experience with rust can view a lot
of points where we can optimize this code. At first I thought that the translation
could be done during the parsing, keeping a length to be able to view backward
and forward.&lt;/p&gt;
&lt;p&gt;Maybe it's possible to read char by char, keeping a buffer, and detecting if
we can apply any of the rules with the content in the buffer, but I've based
this lib in the python one, so for me it was easier to translate each regex to
pest regex and then do the same translations in the lib.&lt;/p&gt;
&lt;p&gt;But I still think that there's a better solution for this problem, but some times
it's better to have something that just works instead of a never done best
solution.&lt;/p&gt;
&lt;p&gt;During this process I've learned to use pest and I've been playing a lot with
regular expressions, so it was a fun project.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 06 Jul 2019 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2019-07-06:/andaluh.html</guid><category>content</category><category>gnome</category><category>software</category><category>andaluh</category><category>language</category></item></channel></rss>