Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
216682498d | |||
d5c3259225 | |||
7e24ad39b1 | |||
77c2d0ea4a | |||
d1bbadfbd6 | |||
69cf5566cf | |||
ea97af4f12 | |||
07c1fe51fb | |||
6096052962 |
2
.gitignore
vendored
@ -130,3 +130,5 @@ $RECYCLE.BIN/
|
|||||||
*.lnk
|
*.lnk
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/c,macos,windows,linux,c
|
# End of https://www.toptal.com/developers/gitignore/api/c,macos,windows,linux,c
|
||||||
|
|
||||||
|
build/
|
||||||
|
1
Makefile
@ -34,6 +34,7 @@ prep:
|
|||||||
-@mkdir -p $(IDIR)
|
-@mkdir -p $(IDIR)
|
||||||
-@mkdir -p $(ODIR)
|
-@mkdir -p $(ODIR)
|
||||||
-@mkdir -p $(BINDIR)
|
-@mkdir -p $(BINDIR)
|
||||||
|
@echo $(BINDIR)/ >> .gitignore
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
109
README.md
@ -1,12 +1,41 @@
|
|||||||
# lat
|
# lat
|
||||||
> lat | lazy cat - a cat clone with some quality-of-life embellishments
|
> lat | lazy cat - a cat clone with some quality-of-life embellishments
|
||||||
|
|
||||||
|
[](https://github.com/secondary-smiles/lat/actions/workflows/c-cpp.yml)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
`lat` is a solution to a problem that doesn't exist. It's the awkward middle child in-between `cat` and `bat`. It was created because the author didn't want to have to configure `bat` just to get decent file printing, but wanted a little more control than `cat` offered.
|
`lat` is a solution to a problem that doesn't exist. It's the awkward middle child in-between `cat` and `bat`. It was created because the author didn't want to have to configure `bat` just to get decent file printing, but wanted a little more control than `cat` offered.
|
||||||
|
|
||||||
`lat` does not expect to be used. `lat` expects to be forgotten and shunted into a corner because it does not belong in the slightest.
|
`lat` does not expect to be used. `lat` expects to be forgotten and shunted into a corner because it does not belong in the slightest.
|
||||||
|
|
||||||
|
`lat` is fast. Here are the hyperfine results comparing `cat`, `lat`, and `bat` on a ~24MB text file:
|
||||||
|
|
||||||
|
```test
|
||||||
|
❯ hyperfine "cat log.log" "lat log.log" "bat log.log" -N --warmup 200
|
||||||
|
Benchmark 1: cat log.log
|
||||||
|
Time (mean ± σ): 3.6 ms ± 0.3 ms [User: 0.4 ms, System: 2.3 ms]
|
||||||
|
Range (min … max): 3.1 ms … 5.0 ms 851 runs
|
||||||
|
|
||||||
|
Benchmark 2: lat log.log
|
||||||
|
Time (mean ± σ): 6.2 ms ± 0.7 ms [User: 0.4 ms, System: 4.2 ms]
|
||||||
|
Range (min … max): 5.5 ms … 14.5 ms 496 runs
|
||||||
|
|
||||||
|
Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
|
||||||
|
|
||||||
|
Benchmark 3: bat log.log
|
||||||
|
Time (mean ± σ): 103.9 ms ± 0.5 ms [User: 37.5 ms, System: 65.6 ms]
|
||||||
|
Range (min … max): 103.2 ms … 104.8 ms 28 runs
|
||||||
|
|
||||||
|
Summary
|
||||||
|
'cat log.log' ran
|
||||||
|
1.74 ± 0.26 times faster than 'lat log.log'
|
||||||
|
29.10 ± 2.85 times faster than 'bat log.log'
|
||||||
|
```
|
||||||
|
> tested on a 2020 M1 MacBook Pro 16GB
|
||||||
|
|
||||||
|
as you can see, the extra features do take their toll on performance, but overall, `lat` is generally nearly on-par with `cat`, and *far* faster than `bat`.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
`lat` is not yet at a stable version (`v1.0.0`), so it is not on any package managers.
|
`lat` is not yet at a stable version (`v1.0.0`), so it is not on any package managers.
|
||||||
|
|
||||||
@ -15,6 +44,7 @@ git clone https://github.com/secondary-smiles/lat.git
|
|||||||
|
|
||||||
cd lat
|
cd lat
|
||||||
|
|
||||||
|
make prep
|
||||||
make
|
make
|
||||||
|
|
||||||
./build/lat -V
|
./build/lat -V
|
||||||
@ -22,26 +52,95 @@ make
|
|||||||
# now add lat to your $PATH/do whatever you want with the binary
|
# now add lat to your $PATH/do whatever you want with the binary
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Use
|
||||||
|
|
||||||
|
`lat` can, for the most part, be a direct drop in for `cat`. However it really shines when embedded into another program. For example, in `fzf`, `lat` makes an excellent viewer with the command `fzf --command lat -r {}`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Soon, I plan to add the ability to live-write to `lat`. That means that `lat` can become yet another output stream.
|
||||||
|
|
||||||
|
For example, this should be possible in a future version of `lat`
|
||||||
|
|
||||||
|
```c
|
||||||
|
int main(void) {
|
||||||
|
FILE *st = popen("lat -r", "w");
|
||||||
|
if (st == NULL)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
fprintf(st, "look ma, i'm formatted!")
|
||||||
|
|
||||||
|
pclose(st);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> UPDATE: this feature is possible, however the data is only printed upon `pclose`.
|
||||||
|
|
||||||
|
### Features and Flags
|
||||||
|
|
||||||
|
#### `-c` color
|
||||||
|
Completely disables or enables all colored output from `lat`.
|
||||||
|
##### Example
|
||||||
|

|
||||||
|
> `lat` also respects [NO_COLOR](https://no-color.org/), but `-c` overrides it
|
||||||
|
|
||||||
|
#### `-l` line numbers
|
||||||
|
Print numbers for each line of the file.
|
||||||
|
##### Example
|
||||||
|

|
||||||
|
|
||||||
|
#### `-t` file title
|
||||||
|
Shows or hides formatted file data headers.
|
||||||
|
##### Example
|
||||||
|

|
||||||
|
|
||||||
|
#### `-b` binary mode
|
||||||
|
By default, `lat` will attempt to detect if the file is printable or not. If the file isn't (e.g. you ran `lat file.pdf`) then lat will enter *`binary mode`*. In *`binary mode`*, `lat` will skip a lot of processing in favor of speed.
|
||||||
|
You can force *`binary mode`* to be `on` or `off` with the flags `-b` and `-bb` respectively.
|
||||||
|
##### Example
|
||||||
|

|
||||||
|
|
||||||
|
#### `-r` raw output
|
||||||
|
`lat` is smart enough to print all non-file characters to a separate filestream. That way, the output of `lat` can be used to con**cat**enate files, the way it was originally meant to be (with `>` or `|`).
|
||||||
|
However, sometimes you want those extra symbols.
|
||||||
|
`-r` prints everything out to the primary filestream (usually `stdout`)
|
||||||
|
##### Example
|
||||||
|

|
||||||
|
|
||||||
|
#### `-p` pager
|
||||||
|
`lat` comes with out-of-the-box support for paging in `less`. If you don't want your file messing up your terminal, just `-p` it.
|
||||||
|
|
||||||
|
### `-n` name
|
||||||
|
`lat` allows you to customize the name of the file shown. This can be useful in demonstrations or when `lat` is embedded in another program.
|
||||||
|
#### Example
|
||||||
|

|
||||||
|
|
||||||
|
##### Example
|
||||||
|

|
||||||
|
|
||||||
|
#### If there is a feature you'd like to see, feel free to make an issue (1x points). If you're feeling especially savvy, make a PR with the feature (10x points).
|
||||||
|
|
||||||
|
|
||||||
## Helptext
|
## Helptext
|
||||||
> `lat -h`
|
> `lat -h`
|
||||||
|
|
||||||
```text
|
```text
|
||||||
lat | lazy cat - a cat clone with some quality-of-life embellishments
|
lat | lazy cat - a cat clone with some quality-of-life embellishments
|
||||||
|
|
||||||
usage: lat [-cltbrpneVh] [file...]
|
usage: lat [-cltbrpnVh] [file...]
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-c toggle color
|
-c toggle color
|
||||||
-l toggle line numbers
|
-l toggle line numbers
|
||||||
-t toggle file info headers
|
-t toggle file info headers
|
||||||
-b set binary mode, -b forces binary and -bb forces NOT binary
|
-b toggle binary mode, -b forces binary and -bb forces NOT binary
|
||||||
-r print everything (headers, line numbers, etc.) to stdout (or equivalent)
|
-r print everything to stdout (or equivalent)
|
||||||
-p print file with the pager (uses less)
|
-p print file with the pager (uses less)
|
||||||
-n <name> manually set the name of the file shown in the title
|
-n set the name of the file in the title
|
||||||
-e <program> link extension to lat
|
|
||||||
-V show program version
|
-V show program version
|
||||||
-h display this help text
|
-h display this help text
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
NO_COLOR, see https://no-color.org/
|
NO_COLOR, see https://no-color.org/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define ARG_H
|
#define ARG_H
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define LAT_VERSION "0.13.0"
|
#define LAT_VERSION "0.12.2"
|
||||||
|
|
||||||
struct config {
|
struct config {
|
||||||
bool isstdin;
|
bool isstdin;
|
||||||
@ -14,7 +14,6 @@ struct config {
|
|||||||
bool literal;
|
bool literal;
|
||||||
bool pager;
|
bool pager;
|
||||||
char *name;
|
char *name;
|
||||||
char *extension;
|
|
||||||
bool has_read_stdin;
|
bool has_read_stdin;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
Require lat
|
|
||||||
Output social/render/lat_demo.gif
|
|
||||||
|
|
||||||
Set Theme "Gruvbox Dark"
|
|
||||||
Set WindowBar Rings
|
|
||||||
Set BorderRadius 10
|
|
||||||
Set Margin 10
|
|
||||||
|
|
||||||
Set FontSize 32
|
|
||||||
Set Width 2400
|
|
||||||
Set Height 2000
|
|
||||||
Set TypingSpeed 0.2
|
|
||||||
|
|
||||||
Type "lat Makefile"
|
|
||||||
Sleep 2s
|
|
||||||
Enter
|
|
||||||
|
|
||||||
Sleep 4s
|
|
||||||
|
|
||||||
Type "lat -h"
|
|
||||||
Sleep 2s
|
|
||||||
Enter
|
|
||||||
|
|
||||||
Sleep 4s
|
|
BIN
social/render/binary.gif
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
social/render/color.gif
Normal file
After Width: | Height: | Size: 411 KiB |
BIN
social/render/fzf_embed.gif
Normal file
After Width: | Height: | Size: 5.1 MiB |
BIN
social/render/headers.gif
Normal file
After Width: | Height: | Size: 408 KiB |
BIN
social/render/line_numbers.gif
Normal file
After Width: | Height: | Size: 247 KiB |
BIN
social/render/literal.gif
Normal file
After Width: | Height: | Size: 413 KiB |
BIN
social/render/name.gif
Normal file
After Width: | Height: | Size: 105 KiB |
BIN
social/render/pager.gif
Normal file
After Width: | Height: | Size: 18 MiB |
@ -1,14 +1,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdnoreturn.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdnoreturn.h>
|
||||||
|
|
||||||
#include "arg.h"
|
#include "arg.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define LAT_SHORT_ARGS "cltbrpn:e:Vh"
|
#define LAT_SHORT_ARGS "cltbrpn:Vh"
|
||||||
#define LAT_USAGE "usage: lat [-cltbrpneVh] [file...]"
|
#define LAT_USAGE "usage: lat [-cltbrpnVh] [file...]"
|
||||||
|
|
||||||
struct config conf;
|
struct config conf;
|
||||||
|
|
||||||
@ -17,20 +16,17 @@ void help(void) {
|
|||||||
"embellishments\n\n");
|
"embellishments\n\n");
|
||||||
|
|
||||||
printf("%s\n\n", LAT_USAGE);
|
printf("%s\n\n", LAT_USAGE);
|
||||||
printf("options:\n"
|
printf(
|
||||||
"\t-c toggle color\n"
|
"options:\n"
|
||||||
"\t-l toggle line numbers\n"
|
"\t-c\t\t toggle color\n"
|
||||||
"\t-t toggle file info headers\n"
|
"\t-l\t\t toggle line numbers\n"
|
||||||
"\t-b set binary mode, -b forces binary and -bb forces NOT "
|
"\t-t\t\t toggle file info headers\n"
|
||||||
"binary\n"
|
"\t-b\t\t set binary mode, -b forces binary and -bb forces NOT binary\n"
|
||||||
"\t-r print everything (headers, line numbers, etc.) to "
|
"\t-r\t\t print everything (headers, line numbers, etc.) to stdout (or equivalent)\n"
|
||||||
"stdout (or equivalent)\n"
|
"\t-p\t\t print file with the pager (uses less)\n"
|
||||||
"\t-p disable or enable pager (uses less)\n"
|
"\t-n <name>\t\t manually set the name of the file in the title\n"
|
||||||
"\t-n <name> manually set the name of the file shown in the title\n"
|
"\t-V\t\t show program version\n"
|
||||||
// "\t-e <program> NONFUNCTIONAL (will be added soon) link extension
|
"\t-h\t\t display this help text\n\n");
|
||||||
// to lat\n"
|
|
||||||
"\t-V show program version\n"
|
|
||||||
"\t-h display this help text\n\n");
|
|
||||||
printf("environment:\n"
|
printf("environment:\n"
|
||||||
"\tNO_COLOR, see https://no-color.org/\n");
|
"\tNO_COLOR, see https://no-color.org/\n");
|
||||||
}
|
}
|
||||||
@ -73,9 +69,6 @@ int parseargs(int argc, char *argv[]) {
|
|||||||
case 'n':
|
case 'n':
|
||||||
conf.name = optarg;
|
conf.name = optarg;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
|
||||||
conf.extension = optarg;
|
|
||||||
break;
|
|
||||||
case 'V':
|
case 'V':
|
||||||
version();
|
version();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
47
src/main.c
@ -1,13 +1,11 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "arg.h"
|
#include "arg.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define INVERT_T "\x1b[7m"
|
#define INVERT_T "\x1b[7m"
|
||||||
#define UINVERT_T "\x1b[27m"
|
#define UINVERT_T "\x1b[27m"
|
||||||
@ -53,25 +51,6 @@ void run(FILE *fp, char *filename, bool tty) {
|
|||||||
struct filedata f;
|
struct filedata f;
|
||||||
f = readfile(fp, conf.isstdin);
|
f = readfile(fp, conf.isstdin);
|
||||||
|
|
||||||
// any/all processing to be done
|
|
||||||
// TODO: maybe multithread?
|
|
||||||
conf.process = (tty && !f.binary);
|
|
||||||
if (conf.process) { // file display processing
|
|
||||||
loadlines(&f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf.extension != NULL) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
struct winsize w;
|
|
||||||
|
|
||||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1 || w.ws_col != 0) {
|
|
||||||
if (w.ws_row <= f.lc + 5) {
|
|
||||||
conf.pager = !conf.pager;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf.pager) {
|
if (conf.pager) {
|
||||||
st = popen("less", "w");
|
st = popen("less", "w");
|
||||||
err = st;
|
err = st;
|
||||||
@ -94,18 +73,21 @@ void run(FILE *fp, char *filename, bool tty) {
|
|||||||
printheadertop(filename, f.binary);
|
printheadertop(filename, f.binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// any/all processing to be done
|
||||||
|
conf.process = (tty && !f.binary);
|
||||||
|
if (conf.process) { // file display processing
|
||||||
|
loadlines(&f);
|
||||||
|
}
|
||||||
|
|
||||||
if (conf.process) {
|
if (conf.process) {
|
||||||
int linecount = 1;
|
int linecount = 1;
|
||||||
for (int i = 0; i < f.lc; i++) {
|
for (int i = 0; i < f.lc; i++) {
|
||||||
if (conf.lines) {
|
if (conf.lines) {
|
||||||
{ // line numbers
|
|
||||||
char *padding = linepad(linecount, f.lc);
|
char *padding = linepad(linecount, f.lc);
|
||||||
fprintf(err, "%s%s%d│%s ", c.grey, padding, i + 1, c.reset);
|
fprintf(st, "%s%s%d│%s ", c.grey, padding, i + 1, c.reset);
|
||||||
free(padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite(f.lines[i].buf, 1, f.lines[i].len, st);
|
fwrite(f.lines[i].buf, 1, f.lines[i].len, st);
|
||||||
fprintf(st, "\n");
|
fprintf(st, "\n");
|
||||||
|
free(padding);
|
||||||
linecount++;
|
linecount++;
|
||||||
} else {
|
} else {
|
||||||
fprintf(st, "%s\n", f.lines[i].buf);
|
fprintf(st, "%s\n", f.lines[i].buf);
|
||||||
@ -115,7 +97,6 @@ void run(FILE *fp, char *filename, bool tty) {
|
|||||||
} else {
|
} else {
|
||||||
fwrite(f.buf, 1, f.buflen, st);
|
fwrite(f.buf, 1, f.buflen, st);
|
||||||
fflush(st);
|
fflush(st);
|
||||||
if (tty)
|
|
||||||
fwrite("\n", 1, 1, err);
|
fwrite("\n", 1, 1, err);
|
||||||
}
|
}
|
||||||
free(f.buf);
|
free(f.buf);
|
||||||
@ -146,7 +127,6 @@ void initconf(void) {
|
|||||||
conf.lines = true;
|
conf.lines = true;
|
||||||
|
|
||||||
conf.name = NULL;
|
conf.name = NULL;
|
||||||
conf.extension = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearstdin(void) {
|
void clearstdin(void) {
|
||||||
@ -170,11 +150,8 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
bool tty = isatty(STDOUT_FILENO);
|
bool tty = isatty(STDOUT_FILENO);
|
||||||
|
|
||||||
int offset = parseargs(argc, argv);
|
|
||||||
|
|
||||||
conf.headers = conf.headers && tty;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
|
int offset = parseargs(argc, argv);
|
||||||
|
|
||||||
tty = tty || conf.literal;
|
tty = tty || conf.literal;
|
||||||
|
|
||||||
|