Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
6e577f1906 | |||
925ba68c3c | |||
|
1577a74d58 | ||
|
ecd9879655 | ||
|
fa8e81e288 | ||
ef68f9c378 | |||
4618e66f55 | |||
0e157084ea | |||
6b227ba908 | |||
7f18ff6773 | |||
36c5d3f68a | |||
e4f517c020 | |||
0f9a68c578 | |||
1c90bf55b1 | |||
36af47eab8 | |||
cf740c34c3 | |||
51588e455b | |||
b7b16197f9 | |||
efd1d76428 | |||
cc842efe0b | |||
2c0eb3aff1 |
2
.gitignore
vendored
@ -130,5 +130,3 @@ $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,7 +34,6 @@ 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,41 +1,12 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
@ -44,7 +15,6 @@ git clone https://github.com/secondary-smiles/lat.git
|
|||||||
|
|
||||||
cd lat
|
cd lat
|
||||||
|
|
||||||
make prep
|
|
||||||
make
|
make
|
||||||
|
|
||||||
./build/lat -V
|
./build/lat -V
|
||||||
@ -52,95 +22,26 @@ 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 [-cltbrpnVh] [file...]
|
usage: lat [-cltbrpneVh] [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 toggle binary mode, -b forces binary and -bb forces NOT binary
|
-b set binary mode, -b forces binary and -bb forces NOT binary
|
||||||
-r print everything to stdout (or equivalent)
|
-r print everything (headers, line numbers, etc.) to stdout (or equivalent)
|
||||||
-p print file with the pager (uses less)
|
-p print file with the pager (uses less)
|
||||||
-n set the name of the file in the title
|
-n <name> manually set the name of the file shown 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.12.2"
|
#define LAT_VERSION "0.13.0"
|
||||||
|
|
||||||
struct config {
|
struct config {
|
||||||
bool isstdin;
|
bool isstdin;
|
||||||
@ -14,6 +14,7 @@ struct config {
|
|||||||
bool literal;
|
bool literal;
|
||||||
bool pager;
|
bool pager;
|
||||||
char *name;
|
char *name;
|
||||||
|
char *extension;
|
||||||
bool has_read_stdin;
|
bool has_read_stdin;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
24
social/lat_demo.tape
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
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
|
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 411 KiB |
Before Width: | Height: | Size: 5.1 MiB |
Before Width: | Height: | Size: 408 KiB |
Before Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 413 KiB |
Before Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 18 MiB |
@ -1,13 +1,14 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdnoreturn.h>
|
#include <stdnoreturn.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "arg.h"
|
#include "arg.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define LAT_SHORT_ARGS "cltbrpn:Vh"
|
#define LAT_SHORT_ARGS "cltbrpn:e:Vh"
|
||||||
#define LAT_USAGE "usage: lat [-cltbrpnVh] [file...]"
|
#define LAT_USAGE "usage: lat [-cltbrpneVh] [file...]"
|
||||||
|
|
||||||
struct config conf;
|
struct config conf;
|
||||||
|
|
||||||
@ -16,17 +17,20 @@ void help(void) {
|
|||||||
"embellishments\n\n");
|
"embellishments\n\n");
|
||||||
|
|
||||||
printf("%s\n\n", LAT_USAGE);
|
printf("%s\n\n", LAT_USAGE);
|
||||||
printf(
|
printf("options:\n"
|
||||||
"options:\n"
|
"\t-c toggle color\n"
|
||||||
"\t-c\t\t toggle color\n"
|
"\t-l toggle line numbers\n"
|
||||||
"\t-l\t\t toggle line numbers\n"
|
"\t-t toggle file info headers\n"
|
||||||
"\t-t\t\t toggle file info headers\n"
|
"\t-b set binary mode, -b forces binary and -bb forces NOT "
|
||||||
"\t-b\t\t set binary mode, -b forces binary and -bb forces NOT binary\n"
|
"binary\n"
|
||||||
"\t-r\t\t print everything (headers, line numbers, etc.) to stdout (or equivalent)\n"
|
"\t-r print everything (headers, line numbers, etc.) to "
|
||||||
"\t-p\t\t print file with the pager (uses less)\n"
|
"stdout (or equivalent)\n"
|
||||||
"\t-n <name>\t\t manually set the name of the file in the title\n"
|
"\t-p disable or enable pager (uses less)\n"
|
||||||
"\t-V\t\t show program version\n"
|
"\t-n <name> manually set the name of the file shown in the title\n"
|
||||||
"\t-h\t\t display this help text\n\n");
|
// "\t-e <program> NONFUNCTIONAL (will be added soon) link extension
|
||||||
|
// 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");
|
||||||
}
|
}
|
||||||
@ -69,6 +73,9 @@ 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,11 +1,13 @@
|
|||||||
|
#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"
|
||||||
@ -51,6 +53,25 @@ 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;
|
||||||
@ -73,21 +94,18 @@ 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(st, "%s%s%d│%s ", c.grey, padding, i + 1, c.reset);
|
fprintf(err, "%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);
|
||||||
@ -97,6 +115,7 @@ 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);
|
||||||
@ -127,6 +146,7 @@ void initconf(void) {
|
|||||||
conf.lines = true;
|
conf.lines = true;
|
||||||
|
|
||||||
conf.name = NULL;
|
conf.name = NULL;
|
||||||
|
conf.extension = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearstdin(void) {
|
void clearstdin(void) {
|
||||||
@ -150,9 +170,12 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
bool tty = isatty(STDOUT_FILENO);
|
bool tty = isatty(STDOUT_FILENO);
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
int offset = parseargs(argc, argv);
|
int offset = parseargs(argc, argv);
|
||||||
|
|
||||||
|
conf.headers = conf.headers && tty;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
|
||||||
tty = tty || conf.literal;
|
tty = tty || conf.literal;
|
||||||
|
|
||||||
for (int i = offset; i < argc; i++) {
|
for (int i = offset; i < argc; i++) {
|
||||||
|