Repository: maaslalani/slides
File: internal/model/model.go (Go)

Code before:

	metaData, exists := meta.New().Parse(slides[0])
	// If the user specifies a custom configuration options
	// skip the first "slide" since this is all configuration
	if exists && len(slides) > 1 {
		slides = slides[1:]
	}

	m.Slides = slides
	m.Author = metaData.Author
	m.Date = time.Now().Format(metaData.Date)
	m.Paging = metaData.Paging
	if m.Theme == nil {
		m.Theme = styles.SelectTheme(metaData.Theme)
	}

	return nil
}

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.WindowSizeMsg:
		m.viewport.Width = msg.Width
		m.viewport.Height = msg.Height
		return m, nil

	case tea.KeyMsg:
		keyPress := msg.String()
		switch keyPress {
		case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
			if m.bufferIsNumeric() {
				m.buffer += keyPress
			} else {
				m.buffer = keyPress
			}
		case "ctrl+c", "q":
			return m, tea.Quit
		case "g":
			switch m.buffer {
			case "g":
				m.Page = m.navigateFirst()
				m.buffer = ""
			default:
				m.buffer = "g"
			}
		case "G":
			if m.bufferIsNumeric() {
				m.Page = m.navigatePage()
			} else {
				m.Page = m.navigateLast()
			}

Review comment (refactor):
The functionality works great, but I'm a little concerned with all the code living inside the `model.go` file.
What do you think about making this functionality less intertwined with the `model` and have it almost be stateless. I'm thinking we could define a function called `Navigate` inside a new `navigation` package which would define a function:

```go
// Navigate receives the current buffer, keyPress and current page
// and returns the new (updated) buffer and the page to which we should navigate
func Navigate(buffer, keyPress string, page int) (string, int) {
    // Implementation
}
```

The in the `model` we could simply pass all keyPresses with the buffer and current page to the `navigation.Navigate` method and update the buffer and the page. This would also be much easier to test since we can just test the buffer behaviour.

This is extremely great work though, I tested it out and everything works perfectly, so I'm also fine to merge this as is and then work on the refactor myself 😄 . 

Code after:
	// If the user specifies a custom configuration options
	// skip the first "slide" since this is all configuration
	if exists && len(slides) > 1 {
		slides = slides[1:]
	}

	m.Slides = slides
	m.Author = metaData.Author
	m.Date = time.Now().Format(metaData.Date)
	m.Paging = metaData.Paging
	if m.Theme == nil {
		m.Theme = styles.SelectTheme(metaData.Theme)
	}

	return nil
}

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.WindowSizeMsg:
		m.viewport.Width = msg.Width
		m.viewport.Height = msg.Height
		return m, nil

	case tea.KeyMsg:
		keyPress := msg.String()

		switch keyPress {
		case "ctrl+e":
			// Run code blocks
			blocks, err := code.Parse(m.Slides[m.Page])
			if err != nil {
				// We couldn't parse the code block on the screen
				m.VirtualText = "\n" + err.Error()
				return m, nil
			}
			var outs []string
			for _, block := range blocks {
				res := code.Execute(block)
				outs = append(outs, res.Out)
			}
			m.VirtualText = strings.Join(outs, "\n")
		case "ctrl+c", "q":
			return m, tea.Quit
		default:
			newState := navigation.Navigate(navigation.State{
				Buffer:    m.buffer,
				Slide:     m.Page,
				NumSlides: len(m.Slides),
			}, keyPress)
			if newState.Slide != m.Page {