Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions cmd/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"fmt"
"log"
"path/filepath"
"slices"

"github.com/notnmeyer/daylog-cli/internal/daylog"
"github.com/notnmeyer/daylog-cli/internal/file"
"github.com/spf13/cobra"
)

type ShowConfig struct {
Output string
var outputFormats = []string{
"markdown", "md",
"text",
"web",
}

var showCmd = &cobra.Command{
Expand Down Expand Up @@ -42,6 +45,10 @@ var showCmd = &cobra.Command{
dl.Path = filepath.Join(dl.ProjectPath, prev, "log.md")
}

if !validOutputFormat(format) {
log.Fatalf("output must be one of %v\n", outputFormats)
}

logContents, err := dl.Show(format)
if err != nil {
log.Fatalf("%s", err.Error())
Expand All @@ -53,5 +60,13 @@ var showCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(showCmd)
showCmd.PersistentFlags().StringP("output", "o", "markdown", "Format output")
showCmd.PersistentFlags().StringP("output", "o", "markdown", fmt.Sprintf("Format output %v", outputFormats))
}

func validOutputFormat(format string) bool {
if slices.Contains(outputFormats, format) {
return true
}

return false
}
46 changes: 46 additions & 0 deletions internal/daylog/daylog.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package daylog

import (
"encoding/base64"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"time"

"github.com/adrg/xdg"
"github.com/markusmobius/go-dateparser"
"github.com/notnmeyer/daylog-cli/internal/editor"
"github.com/notnmeyer/daylog-cli/internal/git"
"github.com/notnmeyer/daylog-cli/internal/output-formatter"
"github.com/notnmeyer/daylog-cli/internal/server"
)

type DayLog struct {
Expand Down Expand Up @@ -77,6 +83,27 @@ func (d *DayLog) Show(format string) (string, error) {
return "", err
}

if format == "web" {
fmt.Printf("opening \"%s\" in your browser...", d.Path)

var wg sync.WaitGroup
wg.Add(1)

// start the server in a goroutine
go server.Start(&wg)

// build the url and open it in a browser
data := base64.StdEncoding.EncodeToString([]byte(contents))
url := fmt.Sprintf("http://localhost:8000/show?content=%s", data)
// fmt.Println(url)
open(url)

// wait until the request has been served
wg.Wait()

return "", nil
}

contents, err = outputFormatter.Format(format, contents)
if err != nil {
return "", err
Expand Down Expand Up @@ -203,3 +230,22 @@ func createIfMissing(d *DayLog) error {

return nil
}

// calls "open" or whatever the platform equivilent is on a url
func open(url string) {
var err error
switch runtime.GOOS {
case "linux":
err = exec.Command("xdg-open", url).Start()
case "windows":
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
case "darwin":
err = exec.Command("open", url).Start()
default:
log.Fatalf("Unsupported platform")
}

if err != nil {
log.Fatalf("Error opening URL in default browser: %v", err)
}
}
28 changes: 3 additions & 25 deletions internal/output-formatter/output-formatter.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
package outputFormatter

import (
"fmt"

"github.com/charmbracelet/glamour"
)

var MarkdownFormats = []string{
var OutputFormats = []string{
"markdown", "md",
}

var OutputFormats = append(
MarkdownFormats,
"text",
)
"web",
}

func Format(format, content string) (string, error) {
if !contains(OutputFormats, format) {
return "", fmt.Errorf("output must be one of %v\n", OutputFormats)
}

switch format {
case "markdown", "md":
renderer, _ := glamour.NewTermRenderer(
Expand All @@ -36,16 +27,3 @@ func Format(format, content string) (string, error) {

return content, nil
}

func isMarkdownFormat() {

}

func contains(list []string, item string) bool {
for _, val := range list {
if val == item {
return true
}
}
return false
}
36 changes: 36 additions & 0 deletions internal/server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package server

import (
"embed"
"log"
"net/http"
"sync"
)

//go:embed templates/show.html
var fs embed.FS

func showHandler(wg *sync.WaitGroup) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
defer wg.Done()

data, err := fs.ReadFile("templates/show.html")
if err != nil {
http.Error(w, "could not read embedded file", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "text/html")
w.Write(data)
}
}

func Start(wg *sync.WaitGroup) {
server := &http.Server{Addr: ":8000"}

http.HandleFunc("/show", showHandler(wg))

if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("ListenAndServe(): %v", err)
}
}
41 changes: 41 additions & 0 deletions internal/server/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package server

import (
"net/http"
"net/http/httptest"
"strings"
"sync"
"testing"
)

func TestShowHandler(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)

req := httptest.NewRequest("GET", "/show", nil)
w := httptest.NewRecorder()

handler := showHandler(&wg)
handler.ServeHTTP(w, req)

if w.Code != http.StatusOK {
t.Errorf("expected status %d, got %d", http.StatusOK, w.Code)
}

expectedContentType := "text/html"
if contentType := w.Header().Get("Content-Type"); contentType != expectedContentType {
t.Errorf("expected Content-Type %s, got %s", expectedContentType, contentType)
}

body := w.Body.String()
if !strings.Contains(body, "<!DOCTYPE html>") {
t.Error("expected HTML content, got non-HTML response")
}

// we could be more specific but whatever
if !strings.Contains(body, "Daylog") {
t.Error("expected title 'Daylog' in response")
}

wg.Wait()
}
45 changes: 45 additions & 0 deletions internal/server/templates/show.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Daylog - Fighter of the Night Log</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Electrolize:wght@400;600&display=swap"
>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
>
<style>
:root {
--pico-font-family: 'Electrolize', sans-serif;
}
</style>
</head>
<body>
<main class="container" id="content"></main>
<script>
document.addEventListener('DOMContentLoaded', async () => {
const params = new URLSearchParams(window.location.search);
const base64Content = params.get('content');

if (!base64Content) {
document.getElementById('content').innerText = 'No content provided.';
return;
}

try {
const markdown = atob(base64Content);
document.getElementById('content').innerHTML = marked.parse(markdown);
} catch (error) {
document.getElementById('content').innerText = 'Error decoding markdown content: ' + error.message;
}
});
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion tasks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ cmds = ["nix-shell -p ffmpeg ttyd vhs --run \"vhs demo/demo.tape\""]
cmds = ["go run main.go {{.CLI_ARGS}}"]

[tasks.test]
cmds = ["go test ./... -race"]
cmds = ["go test ./... --race {{.CLI_ARGS}}"]

[tasks.release]
cmds = ["git tag {{.CLI_ARGS}}", "git push origin --tags"]
Expand Down