Skip to content

Mateusz1223/WIM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Wim

Wim is a terminal-based text editor developed as a college project.

Authors

  • Mateusz Piasecki

  • Hubert Klimowicz

User manual:

Control keys

  • To enter command mode press Ctrl + ;

  • To explore commands history press or

  • To execute typed command press Enter

  • To exit command mode press Esc

  • To save changes press Ctrl + S

  • To exit application press Ctrl + Q

Commands

  • mv [DIRECTION - l/r/u/d] [COUNT] moves cursor by a given number of positions in a given direction

  • i "[TEXT]" inserts text at the current cursor positions

  • d [COUNT] deletes a given number of characters at the current cursor position

  • f "[PATTERN]" moves cursor to the next occurance of a given pattern if found

  • s saves changes

  • sa "[PATH]" saves file under given path

  • l [PATH] loads file from a given path

  • mc [NAME] "[COMAND / MACRO]" "[COMMAND / MACRO]" ..." creates macro with a given name

Example of macro definition

mc macro1 "f \"abc\"" "d 3" "i \"replacement\""

This macro will replace first encountered "abc" pattern and replace it with "replacement".

NOTE that created macros are saved in a file and thus available even after restarting the application

  • md [NAME] deletes macro with a given name

  • [MACRO NAME] executes defined macro

Screenshots

Screenshot 1



Screenshot 3



Screenshot 2



Dokumentacja (In Polish)

Założenia projektu

Celem projektu było stworzenie konsolowego edytora tekstu. Edytor miał umożliwiać użytkownikowi definiowanie własnych makr usprawniających pracę z tekstem.

Klasy

  • Model - Udostępnia interfejs umożliwiający edycję i zarządzanie plikiem tekstowym.

  • Commandbuffer - Logiczna reprezentacja pola do wpisywania komend.

  • IView - wirtualny interfejs służący do prezentacji stanu programu.

  • AppManager - Klasa zarządzająca aplikacją. Posiada instancje klasy Model, CommandBuffer oraz listę subskrybujących widoków klasy IView. Śledzi tryb w jakim znajduje się program (Edit/Command) i na tej podstawie odpowiednio przekierowuje obsługę zdarzeń wejściowych.

  • ICommand - Klasa bazowa dla polimorficznej implementacji każdej komendy. Można je utworzyć z tekstu, wypisać na strumień wyjściowy oraz wywołać.

  • Macro - Reprezentuje pojedyncze makro, jako zbiór sekwencyjnie wykonywanych komend.

  • MacroDatabase - Przechowuje wszystkie zapisywane makra i zarządza zapisywaniem ich do pliku.

  • CommandParser - Służy do rozpoznawania rodzaju komendy i utworzenia komendy z tekstu.

  • StringDivider - Główna logika parsowania. Służy do rozpoznawania początku i końca zadanego typu podsłowa (argumentu komendy) i zwracania kolejnych argumentów. Użycie polega na wywołaniu metody, przekazując zmienną typu tekstowego, do którego argument może być zapisany.

  • StringEscaper - Klasa odpowiedzialna za kodowanie i dekodowanie znaków " i \, do przetwarzania tekstu otoczonego znakami ".

  • ...Command - Wszystkie klasy o nazwach kończących się na Command (poza ICommand) są oddzielnymi komendami, które można parsować i wywołać.

Klasy zależne od systemu operacyjnego i konkretnej formy prezentacji:

Oryginalnie projekt został stworzony tak, aby działał w systemie operacyjnym Windows i komunikował się z użytkownikiem za pomocą terminala. Został jednak zaprojektowany w taki sposób, aby stworzenie interfejsu graficznego, bądź przeniesienie go na Linuxa wymagało minimalnej ingerencji w istniejącyc kod. W tym celu wydzieliliśmy specyficzne fragmenty kodu.

  • TerminalContoller - pobiera input od użytkownika i przekazuje go do subskrybującego AppManager'a.

  • TerminalView - dziedziczy po klasie View i służy do wyswietlania stanu programu w terminalu.

Graf zależności

Dependencies graph

Wnioski

  1. Pisanie parsera jest trudne. Należy starannie rozważyć wszystkie przypadki brzegowe co do tekstu, który użytkownik może wpisać - jest ich bardzo dużo i z bardzo wysokim prawdopodbieństwem nie wszystkie będą przez programistę zauważone. Pisanie parsera poprzez zastosowanie tzw. builder pattern (StringDivider) wygląda czysto z zewnątrz, natomiast może potencjalnie ograniczać programistę i wymuszać na nim pisanie licznych metod do klasy.
  2. Co do architektury programu jako całości, w tym projektowania obiektowego, należy umieć przewidzieć jak najwięcej rzeczy - tj. należy przewidzieć, czy wcześniej postawiony problem można w ogóle rozwiązać w proponowany sposób i na jakie problemy można natrafić:
  • podczas implementacji: czy nie korzystamy z pól, które mają być prywatne, czy nasza implementacja faktycznie rozwiązuje zadany problem
  • podczas zmian decyzji projektowych: czy ta zmiana wymusi zmiany w innych fragmentach kodu (i jakie?), czy ta zmiana sprawi, że inny fragment kodu przestanie działać?

Niestety, projekty na studiach nie oddają pełnej skali tego problemu, ponieważ postawiony problem jest często jasno zdefiniowany, a wymagania nie zmieniają się. Ponadto, projekty realizowane na studiach są z natury nieduże. Najlepsze, co możemy zrobić w dużym projekcie, to eksperymentować z wcześniej przemyślanymi pomysłami na rozwiązanie wcześniej podzelonego problemu, z różnymi zewnętrznymi serwisami itp.

Napotkane trudności

Podczas realizacji projektu dwukrotnie natrafiliśmy na tak zwane "circular dependency". Winikało to z tego, że nie do końca przemyśleliśmy strukturę projektu przed przytąpieniem do pisania programu. W rezultacie zmarnowaliśmy część czasu na refactoring, którego można było uniknąć. Ta sytuacja jest dobrą nauczką na przyszłość aby gruntownie zaplanować projekt przed przystąpieniem do jego realizacji.

About

Academic project | TUI text editor | C++

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages