Reorganize code and document functions
This commit is contained in:
parent
96b3fc6c52
commit
5752995272
9 changed files with 93 additions and 41 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
||||||
_build
|
_build
|
||||||
|
inputs/
|
||||||
|
|
|
||||||
3
bin/dune
3
bin/dune
|
|
@ -1,2 +1,3 @@
|
||||||
(executable
|
(executable
|
||||||
(name inspector))
|
(name main)
|
||||||
|
(libraries inspector))
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
module State = struct
|
|
||||||
type t = { lines : string array; cursor : int; size : int }
|
|
||||||
|
|
||||||
let create (fname : string) : t =
|
|
||||||
let lines =
|
|
||||||
In_channel.with_open_text fname In_channel.input_lines |> Array.of_list
|
|
||||||
in
|
|
||||||
{ lines; cursor = 0; size = Array.length lines }
|
|
||||||
|
|
||||||
let show_line s : string = s.lines.(s.cursor)
|
|
||||||
|
|
||||||
let rec repl s =
|
|
||||||
print_string "inspector> ";
|
|
||||||
flush stdout;
|
|
||||||
try
|
|
||||||
match read_line () |> String.lowercase_ascii with
|
|
||||||
| "exit" | "quit" -> print_endline "bye"
|
|
||||||
| "next" ->
|
|
||||||
if s.cursor < s.size - 1 then repl { s with cursor = s.cursor + 1 }
|
|
||||||
else repl s
|
|
||||||
| "prev" ->
|
|
||||||
if s.cursor > 0 then repl { s with cursor = s.cursor - 1 } else repl s
|
|
||||||
| "show" ->
|
|
||||||
Printf.printf "[%d]: %s\n" s.cursor (show_line s);
|
|
||||||
repl s
|
|
||||||
| str ->
|
|
||||||
print_endline str;
|
|
||||||
repl s
|
|
||||||
with End_of_file -> print_endline "bye"
|
|
||||||
end
|
|
||||||
|
|
||||||
let () =
|
|
||||||
if Array.length Sys.argv < 2 then (
|
|
||||||
Printf.eprintf "Usage: %s <logfile>\n" (Filename.basename Sys.argv.(0));
|
|
||||||
exit 1);
|
|
||||||
|
|
||||||
let s = State.create Sys.argv.(1) in
|
|
||||||
Printf.printf "Loaded %d lines\n" s.size;
|
|
||||||
|
|
||||||
State.repl s
|
|
||||||
10
bin/main.ml
Normal file
10
bin/main.ml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
let () =
|
||||||
|
let open Inspector in
|
||||||
|
if Array.length Sys.argv < 2 then (
|
||||||
|
Printf.eprintf "Usage: %s <logfile>\n" (Filename.basename Sys.argv.(0));
|
||||||
|
exit 1);
|
||||||
|
|
||||||
|
let s = State.create Sys.argv.(1) in
|
||||||
|
Printf.printf "Loaded %d lines\n" (State.size s);
|
||||||
|
|
||||||
|
Repl.loop s
|
||||||
2
lib/dune
Normal file
2
lib/dune
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
(library
|
||||||
|
(name inspector))
|
||||||
15
lib/repl.ml
Normal file
15
lib/repl.ml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
let rec loop state =
|
||||||
|
print_string "inspector> ";
|
||||||
|
flush stdout;
|
||||||
|
try
|
||||||
|
match read_line () |> String.lowercase_ascii with
|
||||||
|
| "exit" | "quit" -> print_endline "bye"
|
||||||
|
| "next" -> loop (State.next state)
|
||||||
|
| "prev" -> loop (State.prev state)
|
||||||
|
| "show" ->
|
||||||
|
Printf.printf "[%d]: %s\n" (State.cursor state) (State.show_line state);
|
||||||
|
loop state
|
||||||
|
| str ->
|
||||||
|
print_endline str;
|
||||||
|
loop state
|
||||||
|
with End_of_file -> print_endline "bye"
|
||||||
21
lib/repl.mli
Normal file
21
lib/repl.mli
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
(** Interactive command loop for the inspector.
|
||||||
|
|
||||||
|
The REPL (Read–Eval–Print Loop) repeatedly reads commands from standard
|
||||||
|
input and applies them to the current navigation state.
|
||||||
|
|
||||||
|
Each command may update the state (for example moving the cursor) or display
|
||||||
|
information about the current log line.
|
||||||
|
|
||||||
|
The loop continues until the user enters ["quit"] or ["exit"], or until an
|
||||||
|
end-of-file condition is encountered on standard input (for example when
|
||||||
|
pressing Ctrl-D). *)
|
||||||
|
|
||||||
|
val loop : State.t -> unit
|
||||||
|
(** [loop state] starts the interactive command loop.
|
||||||
|
|
||||||
|
The given [state] represents the current navigation state of the loaded log
|
||||||
|
file. Commands executed by the user may derive new states (for example via
|
||||||
|
{!State.next} or {!State.prev}) which are then used in the next iteration of
|
||||||
|
the loop.
|
||||||
|
|
||||||
|
The function runs until the user exits the program. *)
|
||||||
18
lib/state.ml
Normal file
18
lib/state.ml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
type t = { lines : string array; cursor : int }
|
||||||
|
(** Invariant: cursor >= 0 cursor < Array.length lines *)
|
||||||
|
|
||||||
|
let size s = Array.length s.lines
|
||||||
|
let cursor s = s.cursor
|
||||||
|
|
||||||
|
let create (fname : string) : t =
|
||||||
|
let lines =
|
||||||
|
In_channel.with_open_text fname In_channel.input_lines |> Array.of_list
|
||||||
|
in
|
||||||
|
{ lines; cursor = 0 }
|
||||||
|
|
||||||
|
let show_line s : string = s.lines.(s.cursor)
|
||||||
|
|
||||||
|
let next s =
|
||||||
|
if s.cursor < size s - 1 then { s with cursor = s.cursor + 1 } else s
|
||||||
|
|
||||||
|
let prev s = if s.cursor > 0 then { s with cursor = s.cursor - 1 } else s
|
||||||
24
lib/state.mli
Normal file
24
lib/state.mli
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
type t
|
||||||
|
(** Log navigation state.
|
||||||
|
|
||||||
|
A [t] represents a loaded log file and a cursor pointing to the currently
|
||||||
|
active line. *)
|
||||||
|
|
||||||
|
val create : string -> t
|
||||||
|
(** [create file] loads the log file into memory and initializes the cursor at
|
||||||
|
the first line. *)
|
||||||
|
|
||||||
|
val show_line : t -> string
|
||||||
|
(** [show_line s] returns the line currently pointed to by the cursor. *)
|
||||||
|
|
||||||
|
val next : t -> t
|
||||||
|
(** [next s] moves the cursor to the next line if possible. *)
|
||||||
|
|
||||||
|
val prev : t -> t
|
||||||
|
(** [prev s] moves the cursor to the previous line if possible. *)
|
||||||
|
|
||||||
|
val cursor : t -> int
|
||||||
|
(** Current cursor position. *)
|
||||||
|
|
||||||
|
val size : t -> int
|
||||||
|
(** Number of lines in the log. *)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue