PROJECT: Notably


Overview

Notably is for those who prefer to use a desktop app for managing notes. More importantly, Notably is optimized for those who prefer to work with a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, Notably can get your notes taken down faster than traditional GUI apps.

Summary of contributions

  • Major enhancement: Added Notably’s auto correction functionality

    • What it does: Allows Notably to understand mistyped commands from user, as long as it is within a certain configured threshold. This makes it possible for the user to type faster than before, as he/she does not need to worry about wrong spelling anymore.

    • Justification: This feature improves user experience significantly, as it allows our users to type commands without worrying about wrong spelling any longer. This is really crucial, as Notably is a keyboard/CLI first note-taking application; most interactions are done via typing.

    • Highlights:

      • This enhancement calls for good abstraction. Due to the fact that this component is used the suggestions generation and command parsing aspects of Notably, I had to come up with an abstraction that minimize code duplication and at the same time is flexible for future improvements.

      • In addition, this feature requires calculating edit distance. This shows that I am able to incorporate and create suitable wrappers around complex algorithms to be used in a Software Engineering project.

    • Credits: The implementation of the edit distance algorithm is inspired by https://web.stanford.edu/class/cs124/lec/med.pdf.

  • Major enhancement: Wrote Notably’s Markdown to HTML compiler

    • What it does: Allows Notably to compile Markdown into HTML.

    • Justification: This feature improves user experience significantly, as it allows our users to format their notes using the Markdown syntax. This is really crucial, as Notably is a keyboard/CLI first note-taking application; GUI-based text formatting solution would not work well.

    • Highlights: This enhancement requires me to learn basic compilation techniques, such as tokenizing, parsing, and target code generation. Although Markdown is not a complex syntax, building a Markdown to HTML compiler following the techniques prove to be quite challenging.

    • Credits: The implementation of the compiler is inspired by https://github.github.com/gfm/#appendix-a-parsing-strategy.

  • Code contributed: [Functional code] [Test code]

  • Other contributions:

    • Software architecture: Designed Notably’s overall architecture. In addition, I held a meeting with my teammates to get everyone on the same page about Notably’s overall architecture.

    • Community:

    • Tools:

      • Integrated Codecov (code coverage analysis tool) into Notably’s development workflow (#386)

      • Integrated Netlify into Notably’s development workflow

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

Auto correction

Notably will try its best to correct your mistypes automatically, as long as your mistyped inputs are not too far away from the understood commands. This provides you with a more fluid typing experience!

Notably’s auto correction feature works on two aspects of your typing:

  1. It auto corrects command names, where command names refers to open, search, delete, edit, and others. For example, Notably will correct the mistyped command name opne to open.

  2. It auto corrects the Paths of notes. For example, depending on the notes that exist in your database, Notably might correct /Notaby to /Notably.

See the example below for more information.

Example: Auto correcting user input

Even though the user types in the command name opne, Notably is still able to recognise this as an open command.
In addition, the inputted RelativePath Notaby is understood by Notably, even though there’s no note in the database with the title Notaby. Instead, there exists a note in the database with the RelativePath Notably.
After corrections are done, a list of suggestions will be generated as if the user has inputted open -t Notably!
Correction
Figure 1. Demo for the auto correction feature

Markdown (GitHub Flavored Markdown)

We use the term Markdown and GitHub Flavored Markdown interchangably in this document.

Notably supports basic GitHub Flavored Markdown (GFM) as the BODY content of a note. By supporting Markdown, we hope to enhance your typing experience even further. You can simply type your note in Markdown, and it’ll take care of displaying the content of your note in a nice layout for you.

Currently supported syntax of GitHub Flavored Markdown in Notably consists of:

# Level 1 header
## Level 2 header
### Level 3 header
#### Level 4 header
##### Level 5 header
###### Level 6 header
  • Lists and List items

    Currently, only unordered lists are supported. In addition, only the hyphen - symbol is supported to be used as the list bullets.
- List item
- Another list item
  - A nested list item
    - A deeper nested list item
- Last list item
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Proin dictum accumsan nunc sed feugiat.

Example: Writing your note in Markdown

For example, you might write your note as follows:

# Hello Notably

Notably is for those who prefer to use a desktop app for managing notes.
More importantly, Notably is optimized for those who prefer to work with a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI).

## Getting started

- Ensure you have Java `11` or above installed in your Computer.
- Download the latest https://github.com/AY1920S2-CS2103T-W17-2/main/releases[notably.jar]
- Double-click the file to start the app. The Application should start in a few seconds.

(Coming in v2.0) More complete support of Markdown syntax

In our v2.0 release, we’ll be supporting the following additional Markdown syntax:

*This text will get italicised*
**This text will get bold**
~~This text will get a strikethrough treatment~~

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Architecture

ArchitectureDiagram
Figure 2. Architecture Diagram

Design pattern and data flow

The App is built following the Model-View-Controller design pattern.

In addition, the App’s data flow is unidirectional. That is, all user interactions in View will trigger an appropriate handler in Logic, which in turn updates Model and Storage.

Any data/state changes in Model will then propagate back to View automatically through JavaFX’s Property and Binding. In other words, the Observer design pattern is employed; Model is the observable while View is the observer.

In short, the App’s data flow can be summarized as:
ViewLogicModel + StorageView

Architecture-level components

Overall, the App consists of five main components:

  • View: View of the App.

  • Logic: Business logic of the App.

  • Model: In-memory representation of the App’s data/state.

  • Storage: Reads data from, and writes data to, the hard disk.

  • Commons: A collection of classes used by multiple other components.

The first four components, namely View, Logic, Model and Storage:

  • Defines its API in an interface with the same name as the itself, e.g. Logic.java

  • Exposes its functionality using a {Component Name}Manager class, e.g. LogicManager.java

The following classes from Commons plays an important role at the architecture level:

  • LogsCenter : Used by many classes to write log messages to the App’s log file.

  • Compiler : Used mainly by the View to compile Markdown to HTML for displaying notes.

How the architecture components interact with each other

The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command new -t Notably.

ArchitectureSequenceDiagram
Figure 3. Component interactions for the new -t Notably command

Logic

LogicArchitectureDiagram
Figure 4. Architecture of Logic

API : Logic.java

Logic consists of 3 subcomponents:

CorrectionEngine

CorrectionEngineClassDiagram
Figure 5. Class Diagram of the CorrectionEngine Component

The CorrectionEngine component revolves around two API s, namely:

Given below is the Sequence Diagram for interactions within the StringCorrectionEngine (one concrete implementation of CorrectionEngine) component for the correct("uncorrected") API call.

StringCorrectionEngineSequenceDiagram
Figure 6. Interactions inside the StringCorrectionEngine component for the correct("uncorrected") call

Correction Engine

Rationale

CorrectionEngine is needed to enable auto-correction of user inputs, to deliver as good typing experience as possible.

Current implementation

The CorrectionEngine component revolves around two API s, namely:

Two concrete implementations of the CorrectionEngine interface are, namely:

  • The StringCorrectionEngine class, which deals with the correction of plain strings.

  • The AbsolutePathCorrectionEngine class, which deals with the correction of absolute paths. The absolute paths here refer to the address of the notes (or blocks, as we call it) that exist in the App.

Design considerations

  1. CorrectionEngine is built as a standalone module that can be used by both SuggestionEngine and Parser. This decision is made so that code duplication in relation to auto-correction is minimal.

  2. Both CorrectionEngine and EditDistanceCalculator are implemented as interfaces, in an attempt to make the design of the CorrectionEngine component resilient to change. This design enables us to leverage on the strategy pattern to make our CorrectionEngine component more future-proof.

Compiler

CompilerClassDiagram
Figure 7. Class Diagram of the Compiler Component

The Compiler component’s primary usage is to compile Markdown to HTML. Our Compiler component’s design is based off the parsing strategy explained in GitHub’s GFM Specification

Mainly, the Compiler component consists of the following classes:

The concrete implementations of the Block class consist of:

Two of Block's abstract methods are particularly important:

  • Block#next: This method should be implemented by each of Block's implementation in such a way that accepts a single String line and evolve the current Markdown Abstract Syntax Tree further. That way, each of Block's implementation only needs to care about processing the portion of the String line that is relevant to them, before delegating the rest to its children Blocks.

  • Block#toHtml: This method should be implemented by each of Block's implementation in such a way that it returns the HTML representation of the current Block. That way, each of Block's implementation only needs to care about generating its own HTML; the rest can be delegated to its children Blocks.

In short, our Compiler class will first call the Parser#parse method to generate a Markdown Abstract Syntax Tree. After that, the Compiler class will transform the returned Markdown Abstract Syntax Tree into HTML by calling the root DocumentBlock's toHtml method (which will in turn invoke each of its children’s toHtml method).

Given below is the Sequence Diagram for interactions within the Compiler component for the compile(markdown) API call.

CompilerSequenceDiagram
Figure 8. Interactions inside the Compiler component for the compile(markdown) call

Compiler

Rationale

Compiler is needed to enable compilation of Markdown to HTML. By having an Markdown to HTML compiler, we can allow user to format their notes in Markdown, which enhances their note-editing experience tremendously.

Current implementation

The implementation of Compiler is highly inspired by the parsing strategy explained in GitHub’s GFM Specification. Please read more from the specification for a more comprehensive explanation.

Design considerations

Generally speaking, compilers usually consist of several main components, namely a tokenizer, a parser, and a generator. However, this is not the case in our design of the Compiler component:

  1. Leveraging on the fact that Markdown’s syntax is not overly complicated, we decided not to fully adhere to the usual compiler design. Instead, we merged the tokenizer and parser section into our Parser class. This Parser class thus deals converting raw Markdown string into a Markdown Abstract Syntax Tree.

  2. In addition, we opted to not build a standalone generator component. Instead, we make it such that each node in our Markdown Abstract Syntax Tree supports a toHtml method, which returns the HTML representation of the tree starting from itself as a node. This way, we can leverage on OOP’s polymorphism to generate the HTML string out of our Markdown Abstract Syntax Tree a lot easier.