~nasmevka/tmp

tmp/tmp.d -rw-r--r-- 3.5 KiB
8d2a9397Thomas Teixeira wip: using hare instead of D 11 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import std.stdio : writeln, writefln, stderr, File;
import std.path : buildPath;
import std.file : tempDir;
import std.getopt : Option;

immutable string skeletonDir = "~/.config/skeletons";
immutable string saveFile = "tmp.d_last_file";
immutable string defaultPattern = "tmp.XXXXX";

struct ArgvOptions {
	string pattern, skeleton, extension;
	bool last, failed;
	this(const string pattern) { this.pattern = pattern; }
}

char
randomChar() {
	import std.random : rndGen;

	scope(exit) rndGen.popFront();
	char value = rndGen.front % 62;
	switch (value) {
		case 0:  .. case 25: value += 'a';			   break;
		case 26: .. case 51: value = 'A' + value % 26; break;
		default:			 value = '0' + value % 52; break;
	}
	return value;
}

string
patternToFilename(const string pattern) {
	import std.algorithm.iteration : map;
	import std.conv : to;

	return pattern.dup.map!(ch => ch == 'X' ? randomChar() : ch)
		.to!string;
}

void
writeSkeletonToBaseFile(File file, const string skeleton) {
	import std.file : exists, isDir, isFile, readText;
	import std.path : expandTilde;

	if (skeleton.length <= 0) {
		return;
	}
	immutable string dir = expandTilde(skeletonDir);
	if (!(dir.exists && dir.isDir)) {
		stderr.writefln("invalid skeleton directory : %s", skeletonDir);
		return;
	}
	auto skeletonFile = buildPath(dir, skeleton);
	if (!(skeletonFile.exists && skeletonFile.isFile)) {
		stderr.writefln("no %s skeleton file exists", skeleton);
		return;
	}
	file.write(skeletonFile.readText);
}

string
createTempFile(const ArgvOptions opts) {
	string dirname = tempDir();
	string basename = patternToFilename(opts.pattern) ~ '.' ~ opts.extension;
	string filename = buildPath(dirname, basename);

	File file = File(filename, "w");
	scope(exit) file.close;
	writeSkeletonToBaseFile(file, opts.skeleton);
	return filename;
}

File
openSaveFile(string mode) => File(buildPath(tempDir(), saveFile), mode);

void
saveEntry(const string filename) {
	auto saveFile = openSaveFile("w");
	scope(exit) saveFile.close;
	saveFile.writeln(filename);
}

string 
getLastCreation() {
	import std.string : chomp;
	auto saveFile = openSaveFile("r");
	scope(exit) saveFile.close;
	return saveFile.readln.chomp;
}

void
usage(const string prgName, const Option[] opts) {
	import std.algorithm.iteration : reduce;
	import std.algorithm.comparison : max;

	ulong maxLength = reduce!((a, b) => max(a, b.optShort.length + b.optLong.length + 2))(ulong.min, opts);
	stderr.writefln("usage: %s [opts] ext\n\nOptions:", prgName);
	foreach (opt; opts) {
		string combined = opt.optShort ~ ", " ~ opt.optLong;
	    stderr.writefln("  %-*s  %s", maxLength, combined, opt.help);
	}
}

bool
processArgv(string[] argv, ref ArgvOptions opts) {
	import std.getopt : getopt, config;
	auto result = getopt(
		argv, config.caseSensitive, config.passThrough,
		"skeleton|s", "Skeleton filename used as base file content.", &opts.skeleton,
		"pattern|p", "Temporary file pattern. X's are replaced with random char from [a-zA-Z0-9].", &opts.pattern,
		"last|l", "Print the last created file and exit.", &opts.last,
	);
	if (result.helpWanted || (!opts.last && argv.length != 2)) {
		usage(argv[0], result.options);
		return false;
	}

	if (opts.last) {
		return true;
	}
	opts.extension = argv[1];
	return true;
}

int
main(string[] argv) {
	auto opts = ArgvOptions(defaultPattern);
	immutable bool success = processArgv(argv, opts);
	if (!success) {
		return 1;
	}
	if (opts.last) {
		string last = getLastCreation();
		writeln(last);
		return 0;
	}
	string filename = createTempFile(opts);
	saveEntry(filename);
	writeln(filename);
	return 0;
}