summary refs log tree commit diff
path: root/pkgs/tools/text
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/tools/text')
-rw-r--r--pkgs/tools/text/a2ps/default.nix50
-rw-r--r--pkgs/tools/text/agrep/default.nix32
-rw-r--r--pkgs/tools/text/aha/default.nix28
-rw-r--r--pkgs/tools/text/align/default.nix22
-rw-r--r--pkgs/tools/text/amber/default.nix26
-rw-r--r--pkgs/tools/text/anewer/default.nix22
-rw-r--r--pkgs/tools/text/angle-grinder/default.nix25
-rw-r--r--pkgs/tools/text/ansifilter/default.nix37
-rw-r--r--pkgs/tools/text/ascii/default.nix27
-rw-r--r--pkgs/tools/text/asciigraph/default.nix22
-rw-r--r--pkgs/tools/text/boxes/default.nix47
-rw-r--r--pkgs/tools/text/catdoc/default.nix33
-rw-r--r--pkgs/tools/text/catdocx/default.nix31
-rw-r--r--pkgs/tools/text/cconv/default.nix24
-rw-r--r--pkgs/tools/text/chars/default.nix28
-rw-r--r--pkgs/tools/text/choose/default.nix25
-rw-r--r--pkgs/tools/text/chroma/default.nix37
-rw-r--r--pkgs/tools/text/chroma/src.json11
-rw-r--r--pkgs/tools/text/cmigemo/default.nix45
-rw-r--r--pkgs/tools/text/cmigemo/no-http-tool-check.patch23
-rw-r--r--pkgs/tools/text/codesearch/default.nix24
-rw-r--r--pkgs/tools/text/colordiff/default.nix39
-rw-r--r--pkgs/tools/text/coloursum/default.nix24
-rw-r--r--pkgs/tools/text/convertlit/default.nix37
-rw-r--r--pkgs/tools/text/copyright-update/default.nix26
-rw-r--r--pkgs/tools/text/crowdin-cli/default.nix50
-rw-r--r--pkgs/tools/text/csvdiff/default.nix25
-rw-r--r--pkgs/tools/text/csview/default.nix22
-rw-r--r--pkgs/tools/text/csvkit/default.nix42
-rw-r--r--pkgs/tools/text/dadadodo/default.nix27
-rw-r--r--pkgs/tools/text/dcs/default.nix47
-rw-r--r--pkgs/tools/text/dfmt/default.nix27
-rw-r--r--pkgs/tools/text/diction/default.nix23
-rw-r--r--pkgs/tools/text/diffr/default.nix28
-rw-r--r--pkgs/tools/text/diffstat/default.nix27
-rw-r--r--pkgs/tools/text/difftastic/default.nix24
-rw-r--r--pkgs/tools/text/diffutils/default.nix35
-rw-r--r--pkgs/tools/text/dirdiff/default.nix59
-rw-r--r--pkgs/tools/text/dirdiff/dirdiff-2.1-vars.patch32
-rw-r--r--pkgs/tools/text/discount/default.nix47
-rw-r--r--pkgs/tools/text/discount/fix-configure-path.patch12
-rw-r--r--pkgs/tools/text/discount/parallel-make.patch15
-rw-r--r--pkgs/tools/text/dos2unix/default.nix23
-rw-r--r--pkgs/tools/text/each/default.nix25
-rw-r--r--pkgs/tools/text/ebook-tools/default.nix27
-rw-r--r--pkgs/tools/text/enca/default.nix28
-rw-r--r--pkgs/tools/text/enscript/default.nix44
-rw-r--r--pkgs/tools/text/epubcheck/default.nix41
-rw-r--r--pkgs/tools/text/esh/default.nix40
-rw-r--r--pkgs/tools/text/fanficfare/default.nix30
-rw-r--r--pkgs/tools/text/fastmod/default.nix29
-rw-r--r--pkgs/tools/text/frangipanni/default.nix22
-rw-r--r--pkgs/tools/text/fst/default.nix38
-rw-r--r--pkgs/tools/text/gawk/default.nix77
-rw-r--r--pkgs/tools/text/gawk/gawk-with-extensions.nix13
-rw-r--r--pkgs/tools/text/gawk/gawkextlib.nix149
-rw-r--r--pkgs/tools/text/gawk/setup-hook.sh6
-rw-r--r--pkgs/tools/text/gist/default.nix17
-rw-r--r--pkgs/tools/text/gjo/default.nix25
-rw-r--r--pkgs/tools/text/glogg/default.nix40
-rw-r--r--pkgs/tools/text/gnugrep/default.nix70
-rw-r--r--pkgs/tools/text/gnupatch/Allow_input_files_to_be_missing_for_ed-style_patches.patch33
-rw-r--r--pkgs/tools/text/gnupatch/CVE-2018-1000156.patch211
-rw-r--r--pkgs/tools/text/gnupatch/CVE-2018-6951.patch28
-rw-r--r--pkgs/tools/text/gnupatch/CVE-2018-6952.patch28
-rw-r--r--pkgs/tools/text/gnupatch/CVE-2019-13636.patch108
-rw-r--r--pkgs/tools/text/gnupatch/CVE-2019-13638-and-CVE-2018-20969.patch38
-rw-r--r--pkgs/tools/text/gnupatch/default.nix59
-rw-r--r--pkgs/tools/text/gnused/422.nix35
-rw-r--r--pkgs/tools/text/gnused/default.nix39
-rw-r--r--pkgs/tools/text/goawk/default.nix25
-rw-r--r--pkgs/tools/text/gpt2tc/0001-add-python-shebang.patch10
-rw-r--r--pkgs/tools/text/gpt2tc/default.nix44
-rw-r--r--pkgs/tools/text/grin/default.nix23
-rw-r--r--pkgs/tools/text/grip-search/default.nix31
-rw-r--r--pkgs/tools/text/groff/0001-Fix-cross-compilation-by-looking-for-ar.patch46
-rw-r--r--pkgs/tools/text/groff/default.nix133
-rw-r--r--pkgs/tools/text/groff/site.tmac19
-rw-r--r--pkgs/tools/text/gtranslator/default.nix76
-rw-r--r--pkgs/tools/text/gucci/default.nix29
-rw-r--r--pkgs/tools/text/gucci/deps.nix30
-rw-r--r--pkgs/tools/text/hck/default.nix43
-rw-r--r--pkgs/tools/text/highlight/default.nix62
-rw-r--r--pkgs/tools/text/hottext/default.nix40
-rw-r--r--pkgs/tools/text/html-tidy/default.nix32
-rw-r--r--pkgs/tools/text/html2text/default.nix33
-rw-r--r--pkgs/tools/text/hyx/default.nix30
-rw-r--r--pkgs/tools/text/icdiff/default.nix34
-rw-r--r--pkgs/tools/text/igrep/default.nix36
-rw-r--r--pkgs/tools/text/invoice2data/default.nix58
-rw-r--r--pkgs/tools/text/ispell/default.nix38
-rw-r--r--pkgs/tools/text/jbofihe/default.nix29
-rw-r--r--pkgs/tools/text/jsawk/default.nix28
-rw-r--r--pkgs/tools/text/jumanpp/default.nix28
-rw-r--r--pkgs/tools/text/kakasi/default.nix35
-rw-r--r--pkgs/tools/text/kdiff3/default.nix39
-rw-r--r--pkgs/tools/text/kytea/default.nix32
-rw-r--r--pkgs/tools/text/kytea/gcc-O3.patch13
-rw-r--r--pkgs/tools/text/l2md/default.nix32
-rw-r--r--pkgs/tools/text/languagetool/default.nix38
-rw-r--r--pkgs/tools/text/ledger2beancount/default.nix59
-rw-r--r--pkgs/tools/text/link-grammar/default.nix65
-rw-r--r--pkgs/tools/text/lv/default.nix33
-rw-r--r--pkgs/tools/text/m2r/default.nix32
-rw-r--r--pkgs/tools/text/mairix/default.nix26
-rw-r--r--pkgs/tools/text/mairix/mmap.patch161
-rw-r--r--pkgs/tools/text/mark/default.nix24
-rw-r--r--pkgs/tools/text/markdown-pp/default.nix26
-rw-r--r--pkgs/tools/text/mawk/default.nix22
-rw-r--r--pkgs/tools/text/mb2md/default.nix38
-rw-r--r--pkgs/tools/text/mdbook-graphviz/default.nix26
-rw-r--r--pkgs/tools/text/mdbook-katex/default.nix24
-rw-r--r--pkgs/tools/text/mdbook-linkcheck/default.nix33
-rw-r--r--pkgs/tools/text/mdbook-mermaid/default.nix24
-rw-r--r--pkgs/tools/text/mdbook-plantuml/default.nix28
-rw-r--r--pkgs/tools/text/mdbook/default.nix24
-rw-r--r--pkgs/tools/text/mdcat/default.nix57
-rw-r--r--pkgs/tools/text/mecab/base.nix16
-rw-r--r--pkgs/tools/text/mecab/default.nix21
-rw-r--r--pkgs/tools/text/mecab/ipadic.nix18
-rw-r--r--pkgs/tools/text/mecab/nodic.nix9
-rw-r--r--pkgs/tools/text/miller/default.nix24
-rw-r--r--pkgs/tools/text/mir-qualia/default.nix21
-rw-r--r--pkgs/tools/text/mmdoc/default.nix37
-rw-r--r--pkgs/tools/text/morsel/default.nix22
-rw-r--r--pkgs/tools/text/mpage/default.nix32
-rw-r--r--pkgs/tools/text/multitran/data/default.nix27
-rw-r--r--pkgs/tools/text/multitran/libbtree/default.nix21
-rw-r--r--pkgs/tools/text/multitran/libfacet/default.nix26
-rw-r--r--pkgs/tools/text/multitran/libmtquery/default.nix31
-rw-r--r--pkgs/tools/text/multitran/libmtsupport/default.nix21
-rw-r--r--pkgs/tools/text/multitran/mtutils/default.nix34
-rw-r--r--pkgs/tools/text/namazu/default.nix34
-rw-r--r--pkgs/tools/text/nawk/default.nix40
-rw-r--r--pkgs/tools/text/nkf/default.nix21
-rw-r--r--pkgs/tools/text/num-utils/default.nix29
-rw-r--r--pkgs/tools/text/numdiff/default.nix26
-rw-r--r--pkgs/tools/text/odt2txt/default.nix23
-rw-r--r--pkgs/tools/text/opencc/default.nix36
-rwxr-xr-xpkgs/tools/text/papertrail/Gemfile4
-rw-r--r--pkgs/tools/text/papertrail/Gemfile.lock17
-rw-r--r--pkgs/tools/text/papertrail/default.nix31
-rw-r--r--pkgs/tools/text/papertrail/gemset.nix26
-rw-r--r--pkgs/tools/text/par/default.nix42
-rw-r--r--pkgs/tools/text/patchutils/0.3.3.nix7
-rw-r--r--pkgs/tools/text/patchutils/0.4.2.nix8
-rw-r--r--pkgs/tools/text/patchutils/default.nix6
-rw-r--r--pkgs/tools/text/patchutils/drop-comments.patch84
-rw-r--r--pkgs/tools/text/patchutils/generic.nix45
-rw-r--r--pkgs/tools/text/pbgopy/default.nix22
-rw-r--r--pkgs/tools/text/peco/default.nix25
-rw-r--r--pkgs/tools/text/pinyin-tool/default.nix24
-rw-r--r--pkgs/tools/text/platinum-searcher/default.nix24
-rw-r--r--pkgs/tools/text/platinum-searcher/deps.nix83
-rw-r--r--pkgs/tools/text/pn/default.nix24
-rw-r--r--pkgs/tools/text/podiff/default.nix25
-rw-r--r--pkgs/tools/text/poedit/default.nix49
-rw-r--r--pkgs/tools/text/popfile/default.nix60
-rw-r--r--pkgs/tools/text/proselint/default.nix22
-rw-r--r--pkgs/tools/text/pru/Gemfile2
-rw-r--r--pkgs/tools/text/pru/Gemfile.lock13
-rw-r--r--pkgs/tools/text/pru/default.nix24
-rw-r--r--pkgs/tools/text/pru/gemset.nix12
-rw-r--r--pkgs/tools/text/qgrep/default.nix40
-rw-r--r--pkgs/tools/text/qprint/default.nix29
-rw-r--r--pkgs/tools/text/qshowdiff/default.nix27
-rw-r--r--pkgs/tools/text/reckon/Gemfile2
-rw-r--r--pkgs/tools/text/reckon/Gemfile.lock19
-rw-r--r--pkgs/tools/text/reckon/default.nix33
-rw-r--r--pkgs/tools/text/reckon/gemset.nix43
-rw-r--r--pkgs/tools/text/recode/default.nix28
-rw-r--r--pkgs/tools/text/replace/default.nix34
-rw-r--r--pkgs/tools/text/replace/malloc.patch13
-rw-r--r--pkgs/tools/text/rgxg/default.nix18
-rw-r--r--pkgs/tools/text/ripgrep-all/default.nix63
-rw-r--r--pkgs/tools/text/ripgrep/default.nix56
-rw-r--r--pkgs/tools/text/robodoc/default.nix48
-rw-r--r--pkgs/tools/text/rosie/default.nix48
-rw-r--r--pkgs/tools/text/rpl/default.nix38
-rw-r--r--pkgs/tools/text/rpl/remove-argparse-manpage.diff27
-rw-r--r--pkgs/tools/text/rs/default.nix52
-rw-r--r--pkgs/tools/text/rst2html5/default.nix25
-rw-r--r--pkgs/tools/text/ruby-zoom/Gemfile2
-rw-r--r--pkgs/tools/text/ruby-zoom/Gemfile.lock24
-rw-r--r--pkgs/tools/text/ruby-zoom/default.nix18
-rw-r--r--pkgs/tools/text/ruby-zoom/gemset.nix64
-rw-r--r--pkgs/tools/text/runiq/default.nix20
-rw-r--r--pkgs/tools/text/ruplacer/default.nix24
-rw-r--r--pkgs/tools/text/rust-petname/default.nix22
-rw-r--r--pkgs/tools/text/sad/default.nix25
-rw-r--r--pkgs/tools/text/schema2ldif/default.nix33
-rw-r--r--pkgs/tools/text/sd/default.nix34
-rw-r--r--pkgs/tools/text/sgml/jade/default.nix44
-rw-r--r--pkgs/tools/text/sgml/openjade/default.nix27
-rw-r--r--pkgs/tools/text/sgml/openjade/msggen.patch34
-rw-r--r--pkgs/tools/text/sgml/opensp/default.nix55
-rw-r--r--pkgs/tools/text/sgml/opensp/setup-hook.sh22
-rw-r--r--pkgs/tools/text/shab/default.nix73
-rw-r--r--pkgs/tools/text/shfmt/default.nix37
-rw-r--r--pkgs/tools/text/shocco/default.nix28
-rw-r--r--pkgs/tools/text/sift/default.nix25
-rw-r--r--pkgs/tools/text/sift/deps.nix29
-rw-r--r--pkgs/tools/text/silver-searcher/bash-completion.patch5
-rw-r--r--pkgs/tools/text/silver-searcher/default.nix29
-rw-r--r--pkgs/tools/text/smu/default.nix28
-rw-r--r--pkgs/tools/text/snippetpixie/default.nix91
-rw-r--r--pkgs/tools/text/source-highlight/default.nix63
-rw-r--r--pkgs/tools/text/tab/default.nix40
-rw-r--r--pkgs/tools/text/tidy-viewer/default.nix29
-rw-r--r--pkgs/tools/text/transifex-client/default.nix32
-rw-r--r--pkgs/tools/text/tv/default.nix23
-rw-r--r--pkgs/tools/text/txt2tags/default.nix35
-rw-r--r--pkgs/tools/text/ucg/default.nix58
-rw-r--r--pkgs/tools/text/ugrep/default.nix39
-rw-r--r--pkgs/tools/text/uni2ascii/default.nix41
-rw-r--r--pkgs/tools/text/uniscribe/Gemfile3
-rw-r--r--pkgs/tools/text/uniscribe/Gemfile.lock37
-rw-r--r--pkgs/tools/text/uniscribe/default.nix30
-rw-r--r--pkgs/tools/text/uniscribe/gemset.nix1766
-rw-r--r--pkgs/tools/text/unoconv/default.nix40
-rw-r--r--pkgs/tools/text/unrtf/default.nix31
-rw-r--r--pkgs/tools/text/untex/default.nix29
-rw-r--r--pkgs/tools/text/uwc/default.nix24
-rw-r--r--pkgs/tools/text/vale/default.nix32
-rw-r--r--pkgs/tools/text/vgrep/default.nix32
-rw-r--r--pkgs/tools/text/wdiff/default.nix28
-rw-r--r--pkgs/tools/text/wgetpaste/default.nix30
-rw-r--r--pkgs/tools/text/wrap/default.nix36
-rw-r--r--pkgs/tools/text/xidel/default.nix93
-rw-r--r--pkgs/tools/text/xml/basex/basex.svg81
-rw-r--r--pkgs/tools/text/xml/basex/default.nix67
-rw-r--r--pkgs/tools/text/xml/html-xml-utils/default.nix20
-rw-r--r--pkgs/tools/text/xml/jing-trang/default.nix51
-rw-r--r--pkgs/tools/text/xml/jing-trang/no-git-during-build.patch47
-rw-r--r--pkgs/tools/text/xml/rnv/default.nix20
-rw-r--r--pkgs/tools/text/xml/rxp/default.nix18
-rw-r--r--pkgs/tools/text/xml/xml2/default.nix22
-rw-r--r--pkgs/tools/text/xml/xmldiff/default.nix41
-rw-r--r--pkgs/tools/text/xml/xmlformat/default.nix28
-rw-r--r--pkgs/tools/text/xml/xmloscopy/default.nix53
-rw-r--r--pkgs/tools/text/xml/xmlstarlet/default.nix34
-rw-r--r--pkgs/tools/text/xml/xpf/default.nix21
-rw-r--r--pkgs/tools/text/xsv/default.nix24
-rw-r--r--pkgs/tools/text/xurls/default.nix24
-rw-r--r--pkgs/tools/text/yaml-merge/default.nix29
-rw-r--r--pkgs/tools/text/zimwriterfs/default.nix43
-rw-r--r--pkgs/tools/text/zoekt/default.nix29
-rw-r--r--pkgs/tools/text/zstxtns-utils/default.nix39
248 files changed, 10404 insertions, 0 deletions
diff --git a/pkgs/tools/text/a2ps/default.nix b/pkgs/tools/text/a2ps/default.nix
new file mode 100644
index 00000000000..d3fe3a7e705
--- /dev/null
+++ b/pkgs/tools/text/a2ps/default.nix
@@ -0,0 +1,50 @@
+{ lib, stdenv, fetchurl, fetchpatch, autoconf, bison, libpaper, gperf, file, perl }:
+
+stdenv.mkDerivation rec {
+  pname = "a2ps";
+  version = "4.14";
+
+  src = fetchurl {
+    url = "mirror://gnu/a2ps/a2ps-${version}.tar.gz";
+    sha256 = "195k78m1h03m961qn7jr120z815iyb93gwi159p1p9348lyqvbpk";
+  };
+
+  patches = [
+    (fetchpatch {
+      url = "https://sources.debian.net/data/main/a/a2ps/1:4.14-1.3/debian/patches/09_CVE-2001-1593.diff";
+      sha256 = "1hrfmvb21zlklmg2fqikgywhqgc4qnvbhx517w87faafrhzhlnh0";
+    })
+    (fetchpatch {
+      url = "https://sources.debian.net/data/main/a/a2ps/1:4.14-1.3/debian/patches/CVE-2014-0466.diff";
+      sha256 = "0grqqsc3m45niac56m19m5gx7gc0m8zvia5iman1l4rlq31shf8s";
+    })
+    (fetchpatch {
+      name = "CVE-2015-8107.patch";
+      url = "https://sources.debian.net/data/main/a/a2ps/1:4.14-1.3/debian/patches/fix-format-security.diff";
+      sha256 = "0pq7zl41gf2kc6ahwyjnzn93vbxb4jc2c5g8j20isp4vw6dqrnwv";
+    })
+  ];
+
+  postPatch = ''
+    substituteInPlace afm/make_fonts_map.sh --replace "/bin/rm" "rm"
+    substituteInPlace tests/defs.in --replace "/bin/rm" "rm"
+  '';
+
+  nativeBuildInputs = [ autoconf file bison perl ];
+  buildInputs = [ libpaper gperf ];
+
+  meta = with lib; {
+    description = "An Anything to PostScript converter and pretty-printer";
+    longDescription = ''
+      GNU a2ps converts files into PostScript for printing or viewing. It uses a nice default format,
+      usually two pages on each physical page, borders surrounding pages, headers with useful information
+      (page number, printing date, file name or supplied header), line numbering, symbol substitution as
+      well as pretty printing for a wide range of programming languages.
+    '';
+    homepage = "https://www.gnu.org/software/a2ps/";
+    license = licenses.gpl3Plus;
+    maintainers = [ maintainers.bennofs ];
+    platforms = platforms.linux;
+
+  };
+}
diff --git a/pkgs/tools/text/agrep/default.nix b/pkgs/tools/text/agrep/default.nix
new file mode 100644
index 00000000000..9fe158b426a
--- /dev/null
+++ b/pkgs/tools/text/agrep/default.nix
@@ -0,0 +1,32 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation {
+  pname = "agrep";
+  version = "3.41.5";
+
+  src = fetchFromGitHub {
+    owner = "Wikinaut";
+    repo = "agrep";
+    # This repository has numbered versions, but not Git tags.
+    rev = "eef20411d605d9d17ead07a0ade75046f2728e21";
+    sha256 = "14addnwspdf2mxpqyrw8b84bb2257y43g5ccy4ipgrr91fmxq2sk";
+  };
+
+  # Related: https://github.com/Wikinaut/agrep/pull/11
+  prePatch = lib.optionalString (stdenv.hostPlatform.isMusl || stdenv.isDarwin) ''
+    sed -i '1i#include <sys/stat.h>' checkfil.c newmgrep.c recursiv.c
+  '';
+  installPhase = ''
+    install -Dm 555 agrep -t "$out/bin"
+    install -Dm 444 docs/* -t "$out/doc"
+  '';
+
+  makeFlags = [ "CC=${stdenv.cc.targetPrefix}cc" ];
+
+  meta = with lib; {
+    description = "Approximate grep for fast fuzzy string searching";
+    homepage = "https://www.tgries.de/agrep/";
+    license = licenses.isc;
+    platforms = with platforms; linux ++ darwin;
+  };
+}
diff --git a/pkgs/tools/text/aha/default.nix b/pkgs/tools/text/aha/default.nix
new file mode 100644
index 00000000000..4ac07cef7ee
--- /dev/null
+++ b/pkgs/tools/text/aha/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "aha";
+  version = "0.5.1";
+
+  src = fetchFromGitHub {
+    sha256 = "1gywad0rvvz3c5balz8cxsnx0562hj2ngzqyr8zsy2mb4pn0lpgv";
+    rev = version;
+    repo = "aha";
+    owner = "theZiz";
+  };
+
+  makeFlags = [ "PREFIX=$(out)" ];
+
+  enableParallelBuilding = true;
+
+  meta = with lib; {
+    description = "ANSI HTML Adapter";
+    longDescription = ''
+      aha takes ANSI SGR-coloured input and produces W3C-conformant HTML code.
+    '';
+    homepage = "https://github.com/theZiz/aha";
+    license = with licenses; [ lgpl2Plus mpl11 ];
+    maintainers = with maintainers; [ pSub ];
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/align/default.nix b/pkgs/tools/text/align/default.nix
new file mode 100644
index 00000000000..4f67d747da4
--- /dev/null
+++ b/pkgs/tools/text/align/default.nix
@@ -0,0 +1,22 @@
+{ lib, buildGoModule, fetchFromGitHub }:
+
+buildGoModule rec {
+  pname = "align";
+  version = "1.1.3";
+
+  src = fetchFromGitHub {
+    owner = "Guitarbum722";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "17gs3417633z71kc6l5zqg4b3rjhpn2v8qs8rnfrk4nbwzz4nrq3";
+  };
+
+  vendorSha256 = null;
+
+  meta = with lib; {
+    homepage = "https://github.com/Guitarbum722/align";
+    description = "A general purpose application and library for aligning text";
+    maintainers = with maintainers; [ hrhino ];
+    license = licenses.mit;
+  };
+}
diff --git a/pkgs/tools/text/amber/default.nix b/pkgs/tools/text/amber/default.nix
new file mode 100644
index 00000000000..1cd9e74f194
--- /dev/null
+++ b/pkgs/tools/text/amber/default.nix
@@ -0,0 +1,26 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform
+, libiconv, Security
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "amber";
+  version = "0.5.9";
+
+  src = fetchFromGitHub {
+    owner = "dalance";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-mmgJCD7kJjvpxyagsoe5CSzqIEZcIiYMAMP3axRphv4=";
+  };
+
+  cargoSha256 = "sha256-opRinhTmhZxpAwHNiVOLXL8boQf09Y1NXrWQ6HWQYQ0=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ libiconv Security ];
+
+  meta = with lib; {
+    description = "A code search-and-replace tool";
+    homepage = "https://github.com/dalance/amber";
+    license = with licenses; [ mit ];
+    maintainers = [ maintainers.bdesham ];
+  };
+}
diff --git a/pkgs/tools/text/anewer/default.nix b/pkgs/tools/text/anewer/default.nix
new file mode 100644
index 00000000000..e41b12cee44
--- /dev/null
+++ b/pkgs/tools/text/anewer/default.nix
@@ -0,0 +1,22 @@
+{ lib, rustPlatform, fetchFromGitHub }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "anewer";
+  version = "0.1.6";
+
+  src = fetchFromGitHub {
+    owner = "ysf";
+    repo = pname;
+    rev = version;
+    sha256 = "181mi674354bddnq894yyq587w7skjh35vn61i41vfi6lqz5dy3d";
+  };
+
+  cargoSha256 = "sha256-LJ0l5CZM5NqdbCZe4ELkYf9EkKyBxL/LrNmFy+JS6gM=";
+
+  meta = with lib; {
+    description = "Append lines from stdin to a file if they don't already exist in the file";
+    homepage = "https://github.com/ysf/anewer";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ figsoda ];
+  };
+}
diff --git a/pkgs/tools/text/angle-grinder/default.nix b/pkgs/tools/text/angle-grinder/default.nix
new file mode 100644
index 00000000000..a2303c10a63
--- /dev/null
+++ b/pkgs/tools/text/angle-grinder/default.nix
@@ -0,0 +1,25 @@
+{ lib
+, fetchFromGitHub
+, rustPlatform
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "angle-grinder";
+  version = "0.18.0";
+
+  src = fetchFromGitHub {
+    owner = "rcoh";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-kohw95pvcBLviPgTDGWIbvZuz1cJmKh4eB0Bx4AEk1E=";
+  };
+
+  cargoSha256 = "sha256-m44hFYcyQ1yRf1O5OlomF7rEpkdnnX3FNhB8kUdriKg=";
+
+  meta = with lib; {
+    description = "Slice and dice logs on the command line";
+    homepage = "https://github.com/rcoh/angle-grinder";
+    license = licenses.mit;
+    maintainers = with maintainers; [ bbigras ];
+  };
+}
diff --git a/pkgs/tools/text/ansifilter/default.nix b/pkgs/tools/text/ansifilter/default.nix
new file mode 100644
index 00000000000..79aa4e2debc
--- /dev/null
+++ b/pkgs/tools/text/ansifilter/default.nix
@@ -0,0 +1,37 @@
+{ fetchurl, lib, stdenv, pkg-config, boost, lua }:
+
+stdenv.mkDerivation rec {
+  pname = "ansifilter";
+  version = "2.18";
+
+  src = fetchurl {
+    url = "http://www.andre-simon.de/zip/ansifilter-${version}.tar.bz2";
+    sha256 = "sha256-Zs8BfTakPV9q4gYJzjtYZHSU7mwOQfxoLFmL/859fTk=";
+  };
+
+  nativeBuildInputs = [ pkg-config ];
+  buildInputs = [ boost lua ];
+
+  postPatch = ''
+    substituteInPlace src/makefile --replace "CC=g++" "CC=c++"
+    # avoid timestamp non-determinism with '-n'
+    substituteInPlace makefile --replace 'gzip -9f' 'gzip -9nf'
+  '';
+
+  makeFlags = [
+    "PREFIX=${placeholder "out"}"
+    "conf_dir=/etc/ansifilter"
+  ];
+
+  meta = with lib; {
+    description = "Tool to convert ANSI to other formats";
+    longDescription = ''
+      Tool to remove ANSI or convert them to another format
+      (HTML, TeX, LaTeX, RTF, Pango or BBCode)
+    '';
+    homepage = "http://www.andre-simon.de/doku/ansifilter/en/ansifilter.php";
+    license = licenses.gpl3;
+    maintainers = [ maintainers.Adjective-Object ];
+    platforms = platforms.linux ++ platforms.darwin;
+  };
+}
diff --git a/pkgs/tools/text/ascii/default.nix b/pkgs/tools/text/ascii/default.nix
new file mode 100644
index 00000000000..f596c8d330d
--- /dev/null
+++ b/pkgs/tools/text/ascii/default.nix
@@ -0,0 +1,27 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "ascii";
+  version = "3.18";
+
+  src = fetchurl {
+    url = "http://www.catb.org/~esr/ascii/${pname}-${version}.tar.gz";
+    sha256 = "0b87vy06s8s3a8q70pqavsbk4m4ff034sdml2xxa6qfsykaj513j";
+  };
+
+  prePatch = ''
+    sed -i -e "s|^PREFIX = .*|PREFIX = $out|" Makefile
+  '';
+
+  preInstall = ''
+    mkdir -vp "$out/bin" "$out/share/man/man1"
+  '';
+
+  meta = with lib; {
+    description = "Interactive ASCII name and synonym chart";
+    homepage = "http://www.catb.org/~esr/ascii/";
+    license = licenses.bsd3;
+    platforms = platforms.all;
+    maintainers = [ maintainers.bjornfor ];
+  };
+}
diff --git a/pkgs/tools/text/asciigraph/default.nix b/pkgs/tools/text/asciigraph/default.nix
new file mode 100644
index 00000000000..5cfa00d5326
--- /dev/null
+++ b/pkgs/tools/text/asciigraph/default.nix
@@ -0,0 +1,22 @@
+{ lib, buildGoPackage, fetchFromGitHub }:
+
+buildGoPackage rec {
+  pname = "asciigraph";
+  version = "0.5.3";
+
+  goPackagePath = "github.com/guptarohit/asciigraph";
+
+  src = fetchFromGitHub {
+    owner = "guptarohit";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-GzFJT4LI1QZzghs9g2A+pqkTg68XC+m9F14rYpMxEXM=";
+  };
+
+  meta = with lib; {
+    homepage = "https://github.com/guptarohit/asciigraph";
+    description = "Lightweight ASCII line graph ╭┈╯ command line app";
+    license = licenses.bsd3;
+    maintainers = [ maintainers.mmahut ];
+  };
+}
diff --git a/pkgs/tools/text/boxes/default.nix b/pkgs/tools/text/boxes/default.nix
new file mode 100644
index 00000000000..f39349b2fbf
--- /dev/null
+++ b/pkgs/tools/text/boxes/default.nix
@@ -0,0 +1,47 @@
+{ lib, stdenv, fetchFromGitHub, bison, flex }:
+
+stdenv.mkDerivation rec {
+  pname = "boxes";
+  version = "1.3";
+
+  src = fetchFromGitHub {
+    owner = "ascii-boxes";
+    repo = "boxes";
+    rev = "v${version}";
+    sha256 = "0b12rsynrmkldlwcb62drk33kk0aqwbj10mq5y5x3hjf626gjwsi";
+  };
+
+  # Building instructions:
+  # https://boxes.thomasjensen.com/build.html#building-on-linux--unix
+  nativeBuildInputs = [ bison flex ];
+
+  dontConfigure = true;
+
+  # Makefile references a system wide config file in '/usr/share'. Instead, we
+  # move it within the store by default.
+  preBuild = ''
+    substituteInPlace Makefile \
+      --replace "GLOBALCONF = /usr/share/boxes" \
+                "GLOBALCONF=${placeholder "out"}/share/boxes/boxes-config"
+  '';
+
+  makeFlags = [ "CC=${stdenv.cc.targetPrefix}cc" ];
+
+  installPhase = ''
+    install -Dm755 -t $out/bin src/boxes
+    install -Dm644 -t $out/share/boxes boxes-config
+    install -Dm644 -t $out/share/man/man1 doc/boxes.1
+  '';
+
+  meta = with lib; {
+    description = "Command line ASCII boxes unlimited!";
+    longDescription = ''
+      Boxes is a command line filter program that draws ASCII art boxes around
+      your input text.
+    '';
+    homepage = "https://boxes.thomasjensen.com";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [ waiting-for-dev ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/catdoc/default.nix b/pkgs/tools/text/catdoc/default.nix
new file mode 100644
index 00000000000..db57243efdc
--- /dev/null
+++ b/pkgs/tools/text/catdoc/default.nix
@@ -0,0 +1,33 @@
+{ lib, stdenv, fetchurl, fetchpatch }:
+
+stdenv.mkDerivation rec {
+  pname = "catdoc";
+  version = "0.95";
+
+  src = fetchurl {
+    url = "http://ftp.wagner.pp.ru/pub/catdoc/${pname}-${version}.tar.gz";
+    sha256 = "514a84180352b6bf367c1d2499819dfa82b60d8c45777432fa643a5ed7d80796";
+  };
+
+  patches = [
+    (fetchpatch {
+      url = "https://sources.debian.org/data/main/c/catdoc/1:0.95-4.1/debian/patches/05-CVE-2017-11110.patch";
+      sha256 = "1ljnwvssvzig94hwx8843b88p252ww2lbxh8zybcwr3kwwlcymx7";
+    })
+  ];
+
+  # Remove INSTALL file to avoid `make` misinterpreting it as an up-to-date
+  # target on case-insensitive filesystems e.g. Darwin
+  preInstall = ''
+    rm -v INSTALL
+  '';
+
+  configureFlags = [ "--disable-wordview" ];
+
+  meta = with lib; {
+    description = "MS-Word/Excel/PowerPoint to text converter";
+    platforms = platforms.all;
+    license = licenses.gpl2;
+    maintainers = with maintainers; [];
+  };
+}
diff --git a/pkgs/tools/text/catdocx/default.nix b/pkgs/tools/text/catdocx/default.nix
new file mode 100644
index 00000000000..c762e15c80e
--- /dev/null
+++ b/pkgs/tools/text/catdocx/default.nix
@@ -0,0 +1,31 @@
+{ stdenv, lib, fetchFromGitHub, makeWrapper, unzip, catdoc }:
+
+stdenv.mkDerivation {
+  pname = "catdocx";
+  version = "unstable-2017-01-02";
+
+  src = fetchFromGitHub {
+    owner = "jncraton";
+    repo = "catdocx";
+    rev = "04fa0416ec1f116d4996685e219f0856d99767cb";
+    sha256 = "1sxiqhkvdqn300ygfgxdry2dj2cqzjhkzw13c6349gg5vxfypcjh";
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  installPhase = ''
+    mkdir -p $out/libexec $out/bin
+    cp catdocx.sh $out/libexec
+    chmod +x $out/libexec/catdocx.sh
+    wrapProgram $out/libexec/catdocx.sh --prefix PATH : "${lib.makeBinPath [ unzip catdoc ]}"
+    ln -s $out/libexec/catdocx.sh $out/bin/catdocx
+  '';
+
+  meta = with lib; {
+    description = "Extracts plain text from docx files";
+    homepage = "https://github.com/jncraton/catdocx";
+    license = with licenses; [ bsd3 ];
+    maintainers = [ maintainers.michalrus ];
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/cconv/default.nix b/pkgs/tools/text/cconv/default.nix
new file mode 100644
index 00000000000..de8405aed43
--- /dev/null
+++ b/pkgs/tools/text/cconv/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, autoreconfHook, libiconv }:
+
+stdenv.mkDerivation rec {
+  pname = "cconv";
+  version = "0.6.3";
+
+  src = fetchFromGitHub {
+    owner = "xiaoyjy";
+    repo = "cconv";
+    rev = "v${version}";
+    sha256 = "RAFl/+I+usUfeG/l17F3ltThK7G4+TekyQGwzQIgeH8=";
+  };
+
+  nativeBuildInputs = [ autoreconfHook ];
+  buildInputs = [ libiconv ];
+
+  meta = with lib; {
+    description = "A iconv based simplified-traditional chinese conversion tool";
+    homepage = "https://github.com/xiaoyjy/cconv";
+    license = licenses.mit;
+    platforms = platforms.all;
+    maintainers = [ maintainers.redfish64 ];
+  };
+}
diff --git a/pkgs/tools/text/chars/default.nix b/pkgs/tools/text/chars/default.nix
new file mode 100644
index 00000000000..78caf67bc43
--- /dev/null
+++ b/pkgs/tools/text/chars/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv
+, fetchFromGitHub
+, rustPlatform
+, Security
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "chars";
+  version = "0.6.0";
+
+  src = fetchFromGitHub {
+    owner = "antifuchs";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-aswosSXAh0wkO4N/y/H54dufMDrloWjpjrSWHvHR1rc=";
+  };
+
+  cargoSha256 = "sha256-CqPmasdpXWjCn65G2Ua0h3v+TVP0QPFAdtKOFyoYW/0=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ Security ];
+
+  meta = with lib; {
+    description = "Commandline tool to display information about unicode characters";
+    homepage = "https://github.com/antifuchs/chars";
+    license = licenses.mit;
+    maintainers = with maintainers; [ bbigras ];
+  };
+}
diff --git a/pkgs/tools/text/choose/default.nix b/pkgs/tools/text/choose/default.nix
new file mode 100644
index 00000000000..b214c65b534
--- /dev/null
+++ b/pkgs/tools/text/choose/default.nix
@@ -0,0 +1,25 @@
+{ lib
+, fetchFromGitHub
+, rustPlatform
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "choose";
+  version = "1.3.3";
+
+  src = fetchFromGitHub {
+    owner = "theryangeary";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-HYwlAgFKbi6or2eblERdMMjJOJdtt2FCQECUg3MzO8E=";
+  };
+
+  cargoSha256 = "sha256-55/B+LxdbekfaKKyng0lUCU3QnqL34M+QnLUxaPqkqI=";
+
+  meta = with lib; {
+    description = "A human-friendly and fast alternative to cut and (sometimes) awk";
+    homepage = "https://github.com/theryangeary/choose";
+    license = licenses.gpl3;
+    maintainers = with maintainers; [ sohalt ];
+  };
+}
diff --git a/pkgs/tools/text/chroma/default.nix b/pkgs/tools/text/chroma/default.nix
new file mode 100644
index 00000000000..8b8a8a7b775
--- /dev/null
+++ b/pkgs/tools/text/chroma/default.nix
@@ -0,0 +1,37 @@
+{ lib, buildGoModule, fetchFromGitHub }:
+
+let
+  srcInfo = lib.importJSON ./src.json;
+in
+
+buildGoModule rec {
+  pname = "chroma";
+  version = "0.10.0";
+
+  # To update:
+  # nix-prefetch-git --rev v${version} https://github.com/alecthomas/chroma.git > src.json
+  src = fetchFromGitHub {
+    owner  = "alecthomas";
+    repo   = pname;
+    rev    = "v${version}";
+    inherit (srcInfo) sha256;
+  };
+
+  vendorSha256 = "09b718vjd6npg850fr7z6srs2sc5vsr7byzlz5yb5qx0vm3ajxpf";
+
+  modRoot = "./cmd/chroma";
+
+  # substitute version info as done in goreleaser builds
+  ldflags = [
+    "-X" "main.version=${version}"
+    "-X" "main.commit=${srcInfo.rev}"
+    "-X" "main.date=${srcInfo.date}"
+  ];
+
+  meta = with lib; {
+    homepage = "https://github.com/alecthomas/chroma";
+    description = "A general purpose syntax highlighter in pure Go";
+    license = licenses.mit;
+    maintainers = [ maintainers.sternenseemann ];
+  };
+}
diff --git a/pkgs/tools/text/chroma/src.json b/pkgs/tools/text/chroma/src.json
new file mode 100644
index 00000000000..224bb4328d7
--- /dev/null
+++ b/pkgs/tools/text/chroma/src.json
@@ -0,0 +1,11 @@
+{
+  "url": "https://github.com/alecthomas/chroma.git",
+  "rev": "36bdd4b98823bd1d7be96767cde3dd575e60b406",
+  "date": "2022-01-12T21:49:38+11:00",
+  "path": "/nix/store/951ya4wlxp217a2j3qdni29zwqfq0z7v-chroma",
+  "sha256": "0hjzb61m5lzx95xss82wil9s8f9hbw1zb3jj73ljfwkq5lqk76zq",
+  "fetchLFS": false,
+  "fetchSubmodules": false,
+  "deepClone": false,
+  "leaveDotGit": false
+}
diff --git a/pkgs/tools/text/cmigemo/default.nix b/pkgs/tools/text/cmigemo/default.nix
new file mode 100644
index 00000000000..92be45bbd9d
--- /dev/null
+++ b/pkgs/tools/text/cmigemo/default.nix
@@ -0,0 +1,45 @@
+{ lib, stdenv, fetchFromGitHub, fetchurl, buildPackages
+, gzip, libiconv, nkf, perl, which
+, skk-dicts
+}:
+
+let
+  iconvBin = if stdenv.isDarwin then libiconv else  buildPackages.stdenv.cc.libc;
+in
+stdenv.mkDerivation {
+  pname = "cmigemo";
+  version = "1.3e";
+
+  src = fetchFromGitHub {
+    owner = "koron";
+    repo = "cmigemo";
+    rev = "5c014a885972c77e67d0d17d367d05017c5873f7";
+    sha256 = "0xrblwhaf70m0knkd5584iahaq84rlk0926bhdsrzmakpw77hils";
+  };
+
+  nativeBuildInputs = [ gzip libiconv nkf perl which ];
+
+  postUnpack = ''
+    cp ${skk-dicts}/share/SKK-JISYO.L source/dict/
+  '';
+
+  patches = [ ./no-http-tool-check.patch ];
+
+  makeFlags = [ "INSTALL=install" ];
+
+  preBuild = ''
+    makeFlagsArray+=(FILTER_UTF8="${lib.getBin iconvBin}/bin/iconv -t utf-8 -f cp932")
+  '';
+
+  buildFlags = [ (if stdenv.isDarwin then "osx-all" else "gcc-all") ];
+
+  installTargets = [ (if stdenv.isDarwin then "osx-install" else "gcc-install") ];
+
+  meta = with lib; {
+    description = "A tool that supports Japanese incremental search with Romaji";
+    homepage = "https://www.kaoriya.net/software/cmigemo";
+    license = licenses.mit;
+    maintainers = [ maintainers.cohei ];
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/cmigemo/no-http-tool-check.patch b/pkgs/tools/text/cmigemo/no-http-tool-check.patch
new file mode 100644
index 00000000000..518bfa0e617
--- /dev/null
+++ b/pkgs/tools/text/cmigemo/no-http-tool-check.patch
@@ -0,0 +1,23 @@
+diff --git a/configure b/configure
+index 4480261..2fb9b34 100755
+--- a/configure
++++ b/configure
+@@ -28,18 +28,6 @@ do
+   esac
+ done
+ 
+-# Check HTTP access tool
+-if CHECK_COMMAND curl ; then
+-  PROGRAM_HTTP="curl -O"
+-elif CHECK_COMMAND wget ; then
+-  PROGRAM_HTTP="wget"
+-elif CHECK_COMMAND fetch ; then
+-  PROGRAM_HTTP="fetch"
+-else
+-  echo "ERROR: Require one of HTTP access tools (curl, wget or fetch)."
+-  exit 1
+-fi
+-
+ # Check encoding filter
+ if CHECK_COMMAND qkc ; then
+   PROGRAM_ENCODEFILTER="qkc -q -u"
diff --git a/pkgs/tools/text/codesearch/default.nix b/pkgs/tools/text/codesearch/default.nix
new file mode 100644
index 00000000000..9c3e9fbd840
--- /dev/null
+++ b/pkgs/tools/text/codesearch/default.nix
@@ -0,0 +1,24 @@
+# This file was generated by go2nix.
+{ lib, buildGoPackage, fetchgit }:
+
+buildGoPackage rec {
+  pname = "codesearch";
+  version = "20150717-${lib.strings.substring 0 7 rev}";
+  rev = "a45d81b686e85d01f2838439deaf72126ccd5a96";
+
+  goPackagePath = "github.com/google/codesearch";
+
+  src = fetchgit {
+    inherit rev;
+    url = "https://github.com/google/codesearch";
+    sha256 = "12bv3yz0l3bmsxbasfgv7scm9j719ch6pmlspv4bd4ix7wjpyhny";
+  };
+
+  meta = {
+    description = "Fast, indexed regexp search over large file trees";
+    homepage = "https://github.com/google/codesearch";
+    license = [ lib.licenses.bsd3 ];
+    maintainers = [ lib.maintainers.bennofs ];
+    platforms = lib.platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/colordiff/default.nix b/pkgs/tools/text/colordiff/default.nix
new file mode 100644
index 00000000000..a7e8293851b
--- /dev/null
+++ b/pkgs/tools/text/colordiff/default.nix
@@ -0,0 +1,39 @@
+{ lib, stdenv, fetchFromGitHub, docbook_xml_dtd_412, docbook_xsl, perl, w3m, xmlto, diffutils }:
+
+stdenv.mkDerivation rec {
+  pname = "colordiff";
+  version = "1.0.20";
+
+  src = fetchFromGitHub {
+    owner = "daveewart";
+    repo = "colordiff";
+    rev = "v${version}";
+    sha256 = "sha256-+TtVnUX88LMd8zmhLsKTyR9JlgR7IkUB18PF3LRgPB0=";
+  };
+
+  nativeBuildInputs = [ docbook_xml_dtd_412 docbook_xsl perl w3m xmlto ];
+
+  buildInputs = [ perl ];
+
+  postPatch = ''
+    substituteInPlace Makefile \
+      --replace 'TMPDIR=colordiff-''${VERSION}' ""
+
+    substituteInPlace colordiff.pl \
+      --replace '= "diff";' '= "${diffutils}/bin/diff";'
+  '';
+
+  installFlags = [
+    "INSTALL_DIR=/bin"
+    "MAN_DIR=/share/man/man1"
+    "DESTDIR=${placeholder "out"}"
+  ];
+
+  meta = with lib; {
+    description = "Wrapper for 'diff' that produces the same output but with pretty 'syntax' highlighting";
+    homepage = "https://www.colordiff.org/";
+    license = licenses.gpl2Plus;
+    platforms = platforms.unix;
+    maintainers = with maintainers; [ SuperSandro2000 ];
+  };
+}
diff --git a/pkgs/tools/text/coloursum/default.nix b/pkgs/tools/text/coloursum/default.nix
new file mode 100644
index 00000000000..8391b75a67b
--- /dev/null
+++ b/pkgs/tools/text/coloursum/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, Security }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "coloursum";
+  version = "0.2.0";
+
+  src = fetchFromGitHub {
+    owner = "ticky";
+    repo = "coloursum";
+    rev = "v${version}";
+    sha256 = "1piz0l7qdcvjzfykm6rzqc8s1daxp3cj3923v9cmm41bc2v0p5q0";
+  };
+
+  cargoSha256 = "08l01ivmln9gwabwa1p0gk454qyxlcpnlxx840vys476f4pw7vvf";
+
+  buildInputs = lib.optional stdenv.isDarwin Security;
+
+  meta = with lib; {
+    description = "Colourise your checksum output";
+    homepage = "https://github.com/ticky/coloursum";
+    license = licenses.mit;
+    maintainers = with maintainers; [ fgaz ];
+  };
+}
diff --git a/pkgs/tools/text/convertlit/default.nix b/pkgs/tools/text/convertlit/default.nix
new file mode 100644
index 00000000000..4225934d2d4
--- /dev/null
+++ b/pkgs/tools/text/convertlit/default.nix
@@ -0,0 +1,37 @@
+{lib, stdenv, fetchzip, libtommath}:
+
+stdenv.mkDerivation rec {
+  pname = "convertlit";
+  version = "1.8";
+
+  src = fetchzip {
+    url = "http://www.convertlit.com/convertlit${lib.replaceStrings ["."] [""] version}src.zip";
+    sha256 = "182nsin7qscgbw2h92m0zadh3h8q410h5cza6v486yjfvla3dxjx";
+    stripRoot = false;
+  };
+
+  buildInputs = [libtommath];
+
+  hardeningDisable = [ "format" ];
+
+  buildPhase = ''
+    cd lib
+    make
+    cd ../clit18
+    substituteInPlace Makefile \
+      --replace ../libtommath-0.30/libtommath.a -ltommath
+    make
+  '';
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp clit $out/bin
+  '';
+
+  meta = {
+    homepage = "http://www.convertlit.com/";
+    description = "A tool for converting Microsoft Reader ebooks to more open formats";
+    license = lib.licenses.gpl2;
+    platforms = lib.platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/copyright-update/default.nix b/pkgs/tools/text/copyright-update/default.nix
new file mode 100644
index 00000000000..e0318c20a0e
--- /dev/null
+++ b/pkgs/tools/text/copyright-update/default.nix
@@ -0,0 +1,26 @@
+{ lib, stdenv, fetchFromGitHub, perl }:
+
+stdenv.mkDerivation rec {
+  pname = "copyright-update";
+  version = "2016.1018";
+
+  src = fetchFromGitHub {
+    name = "${pname}-${version}-src";
+    owner = "jaalto";
+    repo = "project--copyright-update";
+    rev = "release/${version}";
+    sha256 = "1kj6jlgyxrgvrpv7fcgbibfqqa83xljp17v6sas42dlb105h6sgd";
+  };
+
+  buildInputs = [ perl ];
+
+  installFlags = [ "INSTALL=install" "prefix=$(out)" ];
+
+  meta = with lib; {
+    homepage = "https://github.com/jaalto/project--copyright-update";
+    description = "Updates the copyright information in a set of files";
+    license = licenses.gpl2Plus;
+    platforms = platforms.all;
+    maintainers = [ maintainers.rycee ];
+  };
+}
diff --git a/pkgs/tools/text/crowdin-cli/default.nix b/pkgs/tools/text/crowdin-cli/default.nix
new file mode 100644
index 00000000000..e73b58d4e6b
--- /dev/null
+++ b/pkgs/tools/text/crowdin-cli/default.nix
@@ -0,0 +1,50 @@
+{ lib
+, stdenv
+, fetchurl
+, gawk
+, git
+, gnugrep
+, installShellFiles
+, jre
+, makeWrapper
+, crowdin-cli
+, testVersion
+, unzip
+}:
+
+stdenv.mkDerivation rec {
+  pname = "crowdin-cli";
+  version = "3.7.8";
+
+  src = fetchurl {
+    url = "https://github.com/crowdin/${pname}/releases/download/${version}/${pname}.zip";
+    sha256 = "sha256-z9c12KKrh4hV7A92qinNCQGTxZI6IsmJ3Z+3ZcZZljk=";
+  };
+
+  nativeBuildInputs = [ installShellFiles makeWrapper unzip ];
+
+  installPhase = ''
+    runHook preInstall
+
+    install -D crowdin-cli.jar $out/lib/crowdin-cli.jar
+
+    installShellCompletion --cmd crowdin --bash ./crowdin_completion
+
+    makeWrapper ${jre}/bin/java $out/bin/crowdin \
+      --argv0 crowdin \
+      --add-flags "-jar $out/lib/crowdin-cli.jar" \
+      --prefix PATH : ${lib.makeBinPath [ gawk gnugrep git ]}
+
+    runHook postInstall
+  '';
+
+  passthru.tests.version = testVersion { package = crowdin-cli; };
+
+  meta = with lib; {
+    mainProgram = "crowdin";
+    homepage = "https://github.com/crowdin/crowdin-cli/";
+    description = "A command-line client for the Crowdin API";
+    license = licenses.mit;
+    maintainers = with maintainers; [ DamienCassou ];
+  };
+}
diff --git a/pkgs/tools/text/csvdiff/default.nix b/pkgs/tools/text/csvdiff/default.nix
new file mode 100644
index 00000000000..f85d725d6ca
--- /dev/null
+++ b/pkgs/tools/text/csvdiff/default.nix
@@ -0,0 +1,25 @@
+{ lib
+, buildGoModule
+, fetchFromGitHub
+}:
+
+buildGoModule rec {
+  pname = "csvdiff";
+  version = "1.4.0";
+
+  src = fetchFromGitHub {
+    owner = "aswinkarthik";
+    repo = "csvdiff";
+    rev = "v${version}";
+    sha256 = "0cd1ikxsypjqisfnmr7zix3g7x8p892w77086465chyd39gpk97b";
+  };
+
+  vendorSha256 = "1612s4kc0r8zw5y2n6agwdx9kwhxkdrjzagn4g22lzmjq02a64xf";
+
+  meta = with lib; {
+    homepage = "https://aswinkarthik.github.io/csvdiff/";
+    description = "A fast diff tool for comparing csv files";
+    license = licenses.mit;
+    maintainers = with maintainers; [ turion ];
+  };
+}
diff --git a/pkgs/tools/text/csview/default.nix b/pkgs/tools/text/csview/default.nix
new file mode 100644
index 00000000000..41ddcfac50a
--- /dev/null
+++ b/pkgs/tools/text/csview/default.nix
@@ -0,0 +1,22 @@
+{ fetchFromGitHub, lib, rustPlatform }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "csview";
+  version = "1.0.1";
+
+  src = fetchFromGitHub {
+    owner = "wfxr";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-tllwFUC+Si3PsYPmiO86D3PNdInuIxxhZW5dAuU4K14=";
+  };
+
+  cargoSha256 = "sha256-j9CwldmxjWYVuiWfAHIV0kr5k/p1BFWHzZiVrv8m7uI=";
+
+  meta = with lib; {
+    description = "A high performance csv viewer with cjk/emoji support";
+    homepage = "https://github.com/wfxr/csview";
+    license = with licenses; [ mit /* or */ asl20 ];
+    maintainers = with maintainers; [ figsoda ];
+  };
+}
diff --git a/pkgs/tools/text/csvkit/default.nix b/pkgs/tools/text/csvkit/default.nix
new file mode 100644
index 00000000000..56f5bae3123
--- /dev/null
+++ b/pkgs/tools/text/csvkit/default.nix
@@ -0,0 +1,42 @@
+{ lib, fetchpatch, python3 }:
+
+python3.pkgs.buildPythonApplication rec {
+  pname = "csvkit";
+  version = "1.0.5";
+
+  src = python3.pkgs.fetchPypi {
+    inherit pname version;
+    sha256 = "1ffmbzk4rxnl1yhqfl58v7kvl5m9cbvjm8v7xp4mvr00sgs91lvv";
+  };
+
+  patches = [
+    # Fixes a failing dbf related test. Won't be needed on 1.0.6 or later.
+    (fetchpatch {
+      url = "https://github.com/wireservice/csvkit/commit/5f22e664121b13d9ff005a9206873a8f97431dca.patch";
+      sha256 = "1kg00z65x7l6dnm5nfsr5krs8m7mv23hhb1inkaqf5m5fpkpnvv7";
+    })
+  ];
+
+  propagatedBuildInputs = with python3.pkgs; [
+    agate
+    agate-excel
+    agate-dbf
+    agate-sql
+    six
+    setuptools
+  ];
+
+  checkInputs = with python3.pkgs; [
+    nose
+    pytestCheckHook
+  ];
+
+  pythonImportsCheck = [ "csvkit" ];
+
+  meta = with lib; {
+    description = "A suite of command-line tools for converting to and working with CSV";
+    maintainers = with maintainers; [ vrthra ];
+    license = licenses.mit;
+    homepage = "https://github.com/wireservice/csvkit";
+  };
+}
diff --git a/pkgs/tools/text/dadadodo/default.nix b/pkgs/tools/text/dadadodo/default.nix
new file mode 100644
index 00000000000..a70a7efda72
--- /dev/null
+++ b/pkgs/tools/text/dadadodo/default.nix
@@ -0,0 +1,27 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "dadadodo";
+  version = "1.04";
+
+  src = fetchurl {
+    url = "https://www.jwz.org/dadadodo/${pname}-${version}.tar.gz";
+    sha256 = "1pzwp3mim58afjrc92yx65mmgr1c834s1v6z4f4gyihwjn8bn3if";
+  };
+
+  makeFlags = [ "CC=${stdenv.cc.targetPrefix}cc" ];
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp dadadodo $out/bin
+  '';
+
+  hardeningDisable = [ "format" ];
+
+  meta = with lib; {
+    description = "Markov chain-based text generator";
+    homepage = "http://www.jwz.org/dadadodo";
+    maintainers = with maintainers; [ pSub ];
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/dcs/default.nix b/pkgs/tools/text/dcs/default.nix
new file mode 100644
index 00000000000..e33c1b44cdf
--- /dev/null
+++ b/pkgs/tools/text/dcs/default.nix
@@ -0,0 +1,47 @@
+{ lib
+, buildGoModule
+, fetchFromGitHub
+, yuicompressor
+, zopfli
+, stdenv
+}:
+buildGoModule {
+  pname = "dcs";
+  version = "unstable-2021-04-07";
+
+  src = fetchFromGitHub {
+    owner = "Debian";
+    repo = "dcs";
+    rev = "da46accc4d55e9bfde1a6852ac5a9e730fcbbb2c";
+    sha256 = "N+6BXlKn1YTlh0ZdPNWa0nuJNcQtlUIc9TocM8cbzQk=";
+  };
+
+  vendorSha256 = "l2mziuisx0HzuP88rS5M+Wha6lu8P036wJYZlmzjWfs=";
+
+  # Depends on dcs binaries
+  doCheck = false;
+
+  nativeBuildInputs = [
+    yuicompressor
+    zopfli
+  ];
+
+  postBuild = ''
+    make -C static -j$NIX_BUILD_CORES
+  '';
+
+  postInstall = ''
+    mkdir -p $out/share/dcs
+    cp -r cmd/dcs-web/templates $out/share/dcs
+    cp -r static $out/share/dcs
+  '';
+
+  meta = with lib; {
+    description = "Debian Code Search";
+    homepage = "https://github.com/Debian/dcs";
+    license = licenses.bsd3;
+    maintainers = teams.determinatesystems.members;
+    broken = stdenv.isAarch64
+      || stdenv.isDarwin; # never built on Hydra https://hydra.nixos.org/job/nixpkgs/staging-next/dcs.x86_64-darwin
+  };
+}
diff --git a/pkgs/tools/text/dfmt/default.nix b/pkgs/tools/text/dfmt/default.nix
new file mode 100644
index 00000000000..16702bb6966
--- /dev/null
+++ b/pkgs/tools/text/dfmt/default.nix
@@ -0,0 +1,27 @@
+{ lib
+, python3
+}:
+
+let
+  inherit (python3.pkgs)
+    buildPythonApplication
+    fetchPypi
+    pythonOlder;
+in
+buildPythonApplication rec {
+  pname = "dfmt";
+  version = "1.2.0";
+  disabled = pythonOlder "3.7";
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "7af6360ca8d556f1cfe82b97f03b8d1ea5a9d6de1fa3018290c844b6566d9d6e";
+  };
+
+  meta = with lib; {
+    description = "Format paragraphs, comments and doc strings";
+    homepage = "https://github.com/dmerejkowsky/dfmt";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ cole-h ];
+  };
+}
diff --git a/pkgs/tools/text/diction/default.nix b/pkgs/tools/text/diction/default.nix
new file mode 100644
index 00000000000..be486cccf54
--- /dev/null
+++ b/pkgs/tools/text/diction/default.nix
@@ -0,0 +1,23 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "diction";
+  version = "1.13";
+
+  src = fetchurl {
+    url = "http://www.moria.de/~michael/diction/${pname}-${version}.tar.gz";
+    sha256 = "08fi971b8qa4xycxbgb42i6b5ms3qx9zpp5hwpbxy2vypfs0wph9";
+  };
+
+  meta = {
+    description = "GNU style and diction utilities";
+    longDescription = ''
+      Diction and style are two old standard Unix commands. Diction identifies
+      wordy and commonly misused phrases. Style analyses surface
+      characteristics of a document, including sentence length and other
+      readability measures.
+    '';
+    license = lib.licenses.gpl3Plus;
+    platforms = lib.platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/diffr/default.nix b/pkgs/tools/text/diffr/default.nix
new file mode 100644
index 00000000000..85d78ffb732
--- /dev/null
+++ b/pkgs/tools/text/diffr/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, Security }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "diffr";
+  version = "0.1.4";
+
+  src = fetchFromGitHub {
+    owner = "mookid";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "18ks5g4bx6iz9hdjxmi6a41ncxpb1hnsscdlddp2gr40k3vgd0pa";
+  };
+
+  cargoSha256 = "0pn3vqv13n29h8069a38306vjlzlxf1m08ldv7lpzgqxhl8an00r";
+
+  buildInputs = (lib.optional stdenv.isDarwin Security);
+
+  preCheck = ''
+    export DIFFR_TESTS_BINARY_PATH=$releaseDir/diffr
+  '';
+
+  meta = with lib; {
+    description = "Yet another diff highlighting tool";
+    homepage = "https://github.com/mookid/diffr";
+    license = with licenses; [ mit ];
+    maintainers = with maintainers; [ davidtwco ];
+  };
+}
diff --git a/pkgs/tools/text/diffstat/default.nix b/pkgs/tools/text/diffstat/default.nix
new file mode 100644
index 00000000000..3e156cf3132
--- /dev/null
+++ b/pkgs/tools/text/diffstat/default.nix
@@ -0,0 +1,27 @@
+{ fetchurl, lib, stdenv }:
+
+stdenv.mkDerivation rec {
+  pname = "diffstat";
+  version = "1.64";
+
+  src = fetchurl {
+    urls = [
+      "ftp://ftp.invisible-island.net/diffstat/diffstat-${version}.tgz"
+      "https://invisible-mirror.net/archives/diffstat/diffstat-${version}.tgz"
+    ];
+    sha256 = "sha256-uK7jjZ0uHQWSbmtVgQqdLC3UB/JNaiZzh1Y6RDbj9/w=";
+  };
+
+  meta = with lib; {
+    description = "Read output of diff and display a histogram of the changes";
+    longDescription = ''
+      diffstat reads the output of diff and displays a histogram of the
+      insertions, deletions, and modifications per-file. It is useful for
+      reviewing large, complex patch files.
+    '';
+    homepage = "https://invisible-island.net/diffstat/";
+    license = licenses.mit;
+    platforms = platforms.unix;
+    maintainers = [ maintainers.bjornfor ];
+  };
+}
diff --git a/pkgs/tools/text/difftastic/default.nix b/pkgs/tools/text/difftastic/default.nix
new file mode 100644
index 00000000000..14c95bd2f3b
--- /dev/null
+++ b/pkgs/tools/text/difftastic/default.nix
@@ -0,0 +1,24 @@
+{ lib, fetchFromGitHub, rustPlatform, tree-sitter }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "difftastic";
+  version = "0.22.0";
+
+  src = fetchFromGitHub {
+    owner = "wilfred";
+    repo = pname;
+    rev = version;
+    sha256 = "sha256-VV4nCR+BGly+EdCkyI4KeS0Zmn6NkfRsMs//0Sj3E20=";
+  };
+
+  cargoSha256 = "sha256-MyCi5PuUs9MJArDFaBgjjBInYJAS/SAPe1iNTs9feLY=";
+
+  meta = with lib; {
+    description = "A syntax-aware diff";
+    homepage = "https://github.com/Wilfred/difftastic";
+    changelog = "https://github.com/Wilfred/difftastic/raw/${version}/CHANGELOG.md";
+    license = licenses.mit;
+    maintainers = with maintainers; [ ethancedwards8 figsoda ];
+    mainProgram = "difft";
+  };
+}
diff --git a/pkgs/tools/text/diffutils/default.nix b/pkgs/tools/text/diffutils/default.nix
new file mode 100644
index 00000000000..d5f27747cf1
--- /dev/null
+++ b/pkgs/tools/text/diffutils/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, fetchurl, xz, coreutils ? null }:
+
+# Note: this package is used for bootstrapping fetchurl, and thus
+# cannot use fetchpatch! All mutable patches (generated by GitHub or
+# cgit) that are needed here should be included directly in Nixpkgs as
+# files.
+
+stdenv.mkDerivation rec {
+  pname = "diffutils";
+  version = "3.8";
+
+  src = fetchurl {
+    url = "mirror://gnu/diffutils/diffutils-${version}.tar.xz";
+    sha256 = "sha256-pr3X0bMSZtEcT03mwbdI1GB6sCMa9RiPwlM9CuJDj+w=";
+  };
+
+  outputs = [ "out" "info" ];
+
+  nativeBuildInputs = [ xz.bin ];
+  /* If no explicit coreutils is given, use the one from stdenv. */
+  buildInputs = [ coreutils ];
+
+  configureFlags =
+    # "pr" need not be on the PATH as a run-time dep, so we need to tell
+    # configure where it is. Covers the cross and native case alike.
+    lib.optional (coreutils != null) "PR_PROGRAM=${coreutils}/bin/pr"
+    ++ lib.optional (stdenv.buildPlatform != stdenv.hostPlatform) "gl_cv_func_getopt_gnu=yes";
+
+  meta = with lib; {
+    homepage = "https://www.gnu.org/software/diffutils/diffutils.html";
+    description = "Commands for showing the differences between files (diff, cmp, etc.)";
+    license = licenses.gpl3;
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/dirdiff/default.nix b/pkgs/tools/text/dirdiff/default.nix
new file mode 100644
index 00000000000..3577242fc0e
--- /dev/null
+++ b/pkgs/tools/text/dirdiff/default.nix
@@ -0,0 +1,59 @@
+{ copyDesktopItems, fetchurl, lib, makeDesktopItem, stdenv, tcl, tk }:
+
+stdenv.mkDerivation rec {
+  pname = "dirdiff";
+  version = "2.1";
+
+  src = fetchurl {
+    url = "mirror://samba/paulus/${pname}-${version}.tar.gz";
+    sha256 = "0lljd8av68j70733yshzzhxjr1lm0vgmbqsm8f02g03qsma3cdyb";
+  };
+
+  nativeBuildInputs = [ copyDesktopItems ];
+  buildInputs = [ tcl tk ];
+
+  # Some light path patching.
+  patches = [ ./dirdiff-2.1-vars.patch ];
+  postPatch = ''
+    for file in dirdiff Makefile; do
+      substituteInPlace "$file" \
+          --subst-var out \
+          --subst-var-by tcl ${tcl} \
+          --subst-var-by tk ${tk}
+    done
+  '';
+
+  # If we don't create the directories ourselves, then 'make install' creates
+  # files named 'bin' and 'lib'.
+  preInstall = ''
+    mkdir -p $out/bin $out/lib
+  '';
+
+  installFlags = [
+    "BINDIR=${placeholder "out"}/bin"
+    "LIBDIR=${placeholder "out"}/lib"
+  ];
+
+  desktopItems = [
+    (makeDesktopItem {
+      name = "dirdiff";
+      exec = "dirdiff";
+      desktopName = "Dirdiff";
+      genericName = "Directory Diff Viewer";
+      comment = "Diff and merge directory trees";
+      categories = [ "Development" ];
+    })
+  ];
+
+  meta = with lib; {
+    description = "Graphical directory tree diff and merge tool";
+    longDescription = ''
+      Dirdiff is a graphical tool for displaying the differences between
+      directory trees and for merging changes from one tree into another.
+    '';
+    homepage = "https://www.samba.org/ftp/paulus/";
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [ khumba ];
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/dirdiff/dirdiff-2.1-vars.patch b/pkgs/tools/text/dirdiff/dirdiff-2.1-vars.patch
new file mode 100644
index 00000000000..4e7aa025754
--- /dev/null
+++ b/pkgs/tools/text/dirdiff/dirdiff-2.1-vars.patch
@@ -0,0 +1,32 @@
+diff '--color=auto' -ru dirdiff-2.1/dirdiff dirdiff-2.1-patched/dirdiff
+--- dirdiff-2.1/dirdiff	2005-04-20 03:09:53.000000000 -0700
++++ dirdiff-2.1-patched/dirdiff	2021-02-14 22:54:09.837692023 -0800
+@@ -1,6 +1,6 @@
+ #!/bin/sh
+ # Tcl ignores the next line \
+-exec wish "$0" -- "${1+$@}"
++exec @tk@/bin/wish "$0" -- "${1+$@}"
+ 
+ # Copyright (C) 1999-2004 Paul Mackerras.  All rights reserved.
+ # This program is free software; it may be used, copied, modified
+@@ -17,7 +17,7 @@
+ set TclExe [info nameofexecutable]
+ set compound_ok [expr {$tcl_version >= 8.4}]
+ 
+-set nofilecmp [catch {load libfilecmp.so.0.0}]
++set nofilecmp [catch {load @out@/lib/libfilecmp.so.0.0}]
+ set rcsflag {}
+ set diffbflag {}
+ set diffBflag {}
+diff '--color=auto' -ru dirdiff-2.1/Makefile dirdiff-2.1-patched/Makefile
+--- dirdiff-2.1/Makefile	2005-04-19 03:22:01.000000000 -0700
++++ dirdiff-2.1-patched/Makefile	2021-02-14 22:54:58.575400923 -0800
+@@ -7,7 +7,7 @@
+ INSTALL=install
+ 
+ # You may need to change the -I arguments depending on your system
+-CFLAGS=-O3 -I/usr/include/tcl8.3/ -I/usr/include/tcl
++CFLAGS=-O3 -I@tcl@/include
+ 
+ all:	libfilecmp.so.0.0
+ 
diff --git a/pkgs/tools/text/discount/default.nix b/pkgs/tools/text/discount/default.nix
new file mode 100644
index 00000000000..dd03bcfa6a3
--- /dev/null
+++ b/pkgs/tools/text/discount/default.nix
@@ -0,0 +1,47 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  version = "2.2.7";
+  pname = "discount";
+
+  src = fetchFromGitHub {
+    owner = "Orc";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "0p2gznrsvv82zxbajqir8y2ap1ribbgagqg1bzhv3i81p2byhjh7";
+  };
+
+  patches = [
+    ./fix-configure-path.patch
+
+    # Fix parallel make depends:
+    # - https://github.com/Orc/discount/commit/e42188e6c4c30d9de668cf98d98dd0c13ecce7cf.patch
+    # - https://github.com/Orc/discount/pull/245
+    ./parallel-make.patch
+  ];
+  configureScript = "./configure.sh";
+
+  configureFlags = [
+    "--enable-all-features"
+    "--pkg-config"
+    "--shared"
+    "--with-fenced-code"
+    # Use deterministic mangling
+    "--debian-glitch"
+  ];
+
+  enableParallelBuilding = true;
+  doCheck = true;
+
+  postFixup = lib.optionalString stdenv.isDarwin ''
+    install_name_tool -id $out/lib/libmarkdown.dylib $out/lib/libmarkdown.dylib
+  '';
+
+  meta = with lib; {
+    description = "Implementation of Markdown markup language in C";
+    homepage = "http://www.pell.portland.or.us/~orc/Code/discount/";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ shell ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/discount/fix-configure-path.patch b/pkgs/tools/text/discount/fix-configure-path.patch
new file mode 100644
index 00000000000..045b369b4b6
--- /dev/null
+++ b/pkgs/tools/text/discount/fix-configure-path.patch
@@ -0,0 +1,12 @@
+diff -rupN discount-2.1.6-original/configure.inc discount-2.1.6/configure.inc
+--- discount-2.1.6-original/configure.inc	2014-10-10 15:34:24.158325345 +0100
++++ discount-2.1.6/configure.inc	2014-10-10 15:34:33.553325321 +0100
+@@ -32,7 +32,7 @@
+ # this preamble code is executed when this file is sourced and it picks
+ # interesting things off the command line.
+ #
+-ac_default_path="/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin"
++ac_default_path=$PATH
+ 
+ ac_standard="--src=DIR		where the source lives (.)
+ --prefix=DIR		where to install the final product (/usr/local)
diff --git a/pkgs/tools/text/discount/parallel-make.patch b/pkgs/tools/text/discount/parallel-make.patch
new file mode 100644
index 00000000000..583622a9152
--- /dev/null
+++ b/pkgs/tools/text/discount/parallel-make.patch
@@ -0,0 +1,15 @@
+https://github.com/Orc/discount/pull/245
+https://github.com/Orc/discount/commit/e42188e6c4c30d9de668cf98d98dd0c13ecce7cf.patch
+
+Fix parallel make failure: add missing pandoc_headers dependency.
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -139,7 +139,7 @@ test:	$(PGMS) $(TESTFRAMEWORK) verify
+ 
+ pandoc_headers.o: tools/pandoc_headers.c config.h
+ 	$(BUILD) -c -o pandoc_headers.o tools/pandoc_headers.c
+-pandoc_headers: pandoc_headers.o
++pandoc_headers: pandoc_headers.o $(COMMON) $(MKDLIB)
+ 	$(LINK) -o pandoc_headers pandoc_headers.o $(COMMON) -lmarkdown 
+ 
+ branch.o: tools/branch.c config.h
diff --git a/pkgs/tools/text/dos2unix/default.nix b/pkgs/tools/text/dos2unix/default.nix
new file mode 100644
index 00000000000..f694b91762c
--- /dev/null
+++ b/pkgs/tools/text/dos2unix/default.nix
@@ -0,0 +1,23 @@
+{lib, stdenv, fetchurl, perl, gettext }:
+
+stdenv.mkDerivation rec {
+  pname = "dos2unix";
+  version = "7.4.2";
+
+  src = fetchurl {
+    url = "https://waterlan.home.xs4all.nl/dos2unix/${pname}-${version}.tar.gz";
+    sha256 = "00dfsf4rfyjb5j12gan8xjiirm0asshdz6dmd3l34a7ays6wadb0";
+  };
+
+  nativeBuildInputs = [ perl gettext ];
+  makeFlags = [ "prefix=${placeholder "out"}" ];
+
+  meta = with lib; {
+    description = "Convert text files with DOS or Mac line breaks to Unix line breaks and vice versa";
+    homepage = "https://waterlan.home.xs4all.nl/dos2unix.html";
+    changelog = "https://sourceforge.net/p/dos2unix/dos2unix/ci/dos2unix-${version}/tree/dos2unix/NEWS.txt?format=raw";
+    license = licenses.bsd2;
+    maintainers = with maintainers; [ c0bw3b ];
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/each/default.nix b/pkgs/tools/text/each/default.nix
new file mode 100644
index 00000000000..0218cf5dde2
--- /dev/null
+++ b/pkgs/tools/text/each/default.nix
@@ -0,0 +1,25 @@
+{ lib
+, fetchFromGitHub
+, rustPlatform
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "each";
+  version = "0.1.3";
+
+  src = fetchFromGitHub {
+    owner = "arraypad";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "04rx8jf871l4darfx6029dhpnbpmzwjgzazayp1qcaadsk8207z5";
+  };
+
+  cargoSha256 = "1r7nzfh7v2mlp0wdrcpqfj68h3zmip2m3d4z2nwxyikmw7c80car";
+
+  meta = with lib; {
+    description = " A better way of working with structured data on the command line";
+    homepage = "https://github.com/arraypad/each";
+    license = with licenses; [ mit ];
+    maintainers = with maintainers; [ thiagokokada ];
+  };
+}
diff --git a/pkgs/tools/text/ebook-tools/default.nix b/pkgs/tools/text/ebook-tools/default.nix
new file mode 100644
index 00000000000..1a46110e2a4
--- /dev/null
+++ b/pkgs/tools/text/ebook-tools/default.nix
@@ -0,0 +1,27 @@
+{ lib, stdenv, fetchurl, cmake, pkg-config, libxml2, libzip }:
+
+stdenv.mkDerivation rec {
+  pname = "ebook-tools";
+  version = "0.2.2";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/ebook-tools/ebook-tools-${version}.tar.gz";
+    sha256 = "1bi7wsz3p5slb43kj7lgb3r6lb91lvb6ldi556k4y50ix6b5khyb";
+  };
+
+  nativeBuildInputs = [ cmake pkg-config ];
+  buildInputs = [ libxml2 libzip ];
+
+  preConfigure =
+    ''
+      NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE $(pkg-config --cflags libzip)"
+    '';
+
+  meta = with lib; {
+    homepage = "http://ebook-tools.sourceforge.net";
+    description = "Tools and library for dealing with various ebook file formats";
+    maintainers = [ ];
+    platforms = platforms.all;
+    license = licenses.mit;
+  };
+}
diff --git a/pkgs/tools/text/enca/default.nix b/pkgs/tools/text/enca/default.nix
new file mode 100644
index 00000000000..7015bd4453c
--- /dev/null
+++ b/pkgs/tools/text/enca/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchurl, libiconv, recode }:
+
+stdenv.mkDerivation rec {
+  pname = "enca";
+  version = "1.19";
+
+  src = fetchurl {
+    url = "https://dl.cihar.com/enca/${pname}-${version}.tar.xz";
+    sha256 = "1f78jmrggv3jymql8imm5m9yc8nqjw5l99mpwki2245l8357wj1s";
+  };
+
+  buildInputs = [ recode libiconv ];
+
+  meta = with lib; {
+    description = "Detects the encoding of text files and reencodes them";
+
+    longDescription = ''
+        Enca detects the encoding of text files, on the basis of knowledge
+        of their language. It can also convert them to other encodings,
+        allowing you to recode files without knowing their current encoding.
+        It supports most of Central and East European languages, and a few
+        Unicode variants, independently on language.
+    '';
+
+    license = licenses.gpl2;
+
+  };
+}
diff --git a/pkgs/tools/text/enscript/default.nix b/pkgs/tools/text/enscript/default.nix
new file mode 100644
index 00000000000..1299ef78679
--- /dev/null
+++ b/pkgs/tools/text/enscript/default.nix
@@ -0,0 +1,44 @@
+{ lib, stdenv, fetchurl, gettext }:
+
+stdenv.mkDerivation rec {
+  pname = "enscript";
+  version = "1.6.6";
+
+  src = fetchurl {
+    url = "mirror://gnu/enscript/enscript-${version}.tar.gz";
+    sha256 = "1fy0ymvzrrvs889zanxcaxjfcxarm2d3k43c9frmbl1ld7dblmkd";
+  };
+
+  preBuild =
+    ''
+      # Fix building on Darwin with GCC.
+      substituteInPlace compat/regex.c --replace \
+         __private_extern__  '__attribute__ ((visibility ("hidden")))'
+    '';
+
+  buildInputs = [ gettext ];
+
+  doCheck = true;
+
+  meta = {
+    description = "Converter from ASCII to PostScript, HTML, or RTF";
+
+    longDescription =
+      '' GNU Enscript converts ASCII files to PostScript, HTML, or RTF and
+         stores generated output to a file or sends it directly to the
+         printer.  It includes features for `pretty-printing'
+         (language-sensitive code highlighting) in several programming
+         languages.
+
+         Enscript can be easily extended to handle different output media and
+         it has many options that can be used to customize printouts.
+      '';
+
+    license = lib.licenses.gpl3Plus;
+
+    homepage = "https://www.gnu.org/software/enscript/";
+
+    maintainers = [ ];
+    platforms = lib.platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/epubcheck/default.nix b/pkgs/tools/text/epubcheck/default.nix
new file mode 100644
index 00000000000..45196422ff5
--- /dev/null
+++ b/pkgs/tools/text/epubcheck/default.nix
@@ -0,0 +1,41 @@
+{ lib, stdenv, fetchzip
+, jre, makeWrapper }:
+
+stdenv.mkDerivation rec {
+  pname = "epubcheck";
+  version = "4.2.6";
+
+  src = fetchzip {
+    url = "https://github.com/w3c/epubcheck/releases/download/v${version}/epubcheck-${version}.zip";
+    sha256 = "sha256-f4r0ODKvZrl+YBcP2T9Z+zEuCyvQm9W7GNiLTr4p278=";
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  dontBuild = true;
+
+  installPhase = ''
+    mkdir -p $out/lib
+    cp -r lib/* $out/lib
+
+    mkdir -p $out/libexec/epubcheck
+    cp epubcheck.jar $out/libexec/epubcheck
+
+    classpath=$out/libexec/epubcheck/epubcheck.jar
+    for jar in $out/lib/*.jar; do
+      classpath="$classpath:$jar"
+    done
+
+    mkdir -p $out/bin
+    makeWrapper ${jre}/bin/java $out/bin/epubcheck \
+      --add-flags "-classpath $classpath com.adobe.epubcheck.tool.Checker"
+  '';
+
+  meta = with lib; {
+    homepage = "https://github.com/w3c/epubcheck";
+    description = "Validation tool for EPUB";
+    license = with licenses; [ asl20 bsd3 mpl10 w3c ];
+    platforms = platforms.all;
+    maintainers = with maintainers; [ eadwu ];
+  };
+}
diff --git a/pkgs/tools/text/esh/default.nix b/pkgs/tools/text/esh/default.nix
new file mode 100644
index 00000000000..a1d6db2a7c2
--- /dev/null
+++ b/pkgs/tools/text/esh/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, fetchFromGitHub, asciidoctor, gawk, gnused, runtimeShell }:
+
+stdenv.mkDerivation rec {
+  pname = "esh";
+  version = "0.1.1";
+
+  src = fetchFromGitHub {
+    owner = "jirutka";
+    repo = "esh";
+    rev = "v${version}";
+    sha256 = "1ddaji5nplf1dyvgkrhqjy8m5djaycqcfhjv30yprj1avjymlj6w";
+  };
+
+  nativeBuildInputs = [ asciidoctor ];
+
+  buildInputs = [ gawk gnused ];
+
+  makeFlags = [ "prefix=$(out)" "DESTDIR=" ];
+
+  postPatch = ''
+    patchShebangs .
+    substituteInPlace esh \
+        --replace '"/bin/sh"' '"${runtimeShell}"' \
+        --replace '"awk"' '"${gawk}/bin/awk"' \
+        --replace 'sed' '${gnused}/bin/sed'
+    substituteInPlace tests/test-dump.exp \
+        --replace '#!/bin/sh' '#!${runtimeShell}'
+  '';
+
+  doCheck = true;
+  checkTarget = "test";
+
+  meta = with lib; {
+    description = "Simple templating engine based on shell";
+    homepage = "https://github.com/jirutka/esh";
+    license = licenses.mit;
+    maintainers = with maintainers; [ mnacamura ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/fanficfare/default.nix b/pkgs/tools/text/fanficfare/default.nix
new file mode 100644
index 00000000000..dec0a194922
--- /dev/null
+++ b/pkgs/tools/text/fanficfare/default.nix
@@ -0,0 +1,30 @@
+{ lib, python3Packages }:
+
+python3Packages.buildPythonApplication rec {
+  pname = "FanFicFare";
+  version = "4.8.0";
+
+  src = python3Packages.fetchPypi {
+    inherit pname version;
+    sha256 = "0h20cw9z6k3z42fhl48pfxcqrk3i45zp4f4xm6pz7jqjzi17h9fk";
+  };
+
+  propagatedBuildInputs = with python3Packages; [
+    beautifulsoup4
+    chardet
+    cloudscraper
+    html5lib
+    html2text
+    requests-file
+  ];
+
+  doCheck = false; # no tests exist
+
+  meta = with lib; {
+    description = "Tool for making eBooks from fanfiction web sites";
+    homepage = "https://github.com/JimmXinu/FanFicFare";
+    license = licenses.gpl3;
+    platforms = platforms.unix;
+    maintainers = with maintainers; [ dwarfmaster ];
+  };
+}
diff --git a/pkgs/tools/text/fastmod/default.nix b/pkgs/tools/text/fastmod/default.nix
new file mode 100644
index 00000000000..d6e2dc4dd1f
--- /dev/null
+++ b/pkgs/tools/text/fastmod/default.nix
@@ -0,0 +1,29 @@
+{ lib, stdenv
+, fetchFromGitHub
+, rustPlatform
+, libiconv
+, Security
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "fastmod";
+  version = "0.4.2";
+
+  src = fetchFromGitHub {
+    owner = "facebookincubator";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-Lv8hARD/aVWiWpJQmPWPeACpX15+3NogoUl5yh63E7A=";
+  };
+
+  cargoSha256 = "sha256-L1MKoVacVKcpEG2IfS+eENxFZNiSaTDTxfFbFlvzYl8=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ libiconv Security ];
+
+  meta = with lib; {
+    description = "A utility that makes sweeping changes to large, shared code bases";
+    homepage = "https://github.com/facebookincubator/fastmod";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ jduan ];
+  };
+}
diff --git a/pkgs/tools/text/frangipanni/default.nix b/pkgs/tools/text/frangipanni/default.nix
new file mode 100644
index 00000000000..58da1a4be4d
--- /dev/null
+++ b/pkgs/tools/text/frangipanni/default.nix
@@ -0,0 +1,22 @@
+{ lib, buildGoModule, fetchFromGitHub }:
+
+buildGoModule rec {
+  pname = "frangipanni";
+  version = "0.5.0";
+
+  src = fetchFromGitHub {
+    owner = "birchb1024";
+    repo = "frangipanni";
+    rev = "v${version}";
+    sha256 = "sha256-jIXyqwZWfCBSDTTodHTct4V5rjYv7h4Vcw7cXOFk17w=";
+  };
+
+  vendorSha256 = "sha256-TSN5M/UCTtfoTf1hDCfrJMCFdSwL/NVXssgt4aefom8=";
+
+  meta = with lib; {
+    description = "Convert lines of text into a tree structure";
+    homepage = "https://github.com/birchb1024/frangipanni";
+    license = licenses.mit;
+    maintainers = with maintainers; [ siraben ];
+  };
+}
diff --git a/pkgs/tools/text/fst/default.nix b/pkgs/tools/text/fst/default.nix
new file mode 100644
index 00000000000..fbd81fbbdbd
--- /dev/null
+++ b/pkgs/tools/text/fst/default.nix
@@ -0,0 +1,38 @@
+{ lib
+, rustPlatform
+, fetchCrate
+, stdenv
+, libiconv
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "fst";
+  version = "0.4.2";
+
+  src = fetchCrate {
+    inherit version;
+    crateName = "fst-bin";
+    sha256 = "sha256-m9JDVHy+o4RYLGkYnhOpTuLyJjXtOwwl2SQpzRuz1m0=";
+  };
+
+  cargoSha256 = "sha256-RMjNk8tE7AYBYgys4IjCCfgPdDgwbYVmrWpWNBOf70E=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ libiconv ];
+
+  doInstallCheck = true;
+  installCheckPhase = ''
+    csv="$(mktemp)"
+    fst="$(mktemp)"
+    printf "abc,1\nabcd,1" > "$csv"
+    $out/bin/fst map "$csv" "$fst" --force
+    $out/bin/fst fuzzy "$fst" 'abc'
+    $out/bin/fst --help > /dev/null
+  '';
+
+  meta = with lib; {
+    description = "Represent large sets and maps compactly with finite state transducers";
+    homepage = "https://github.com/BurntSushi/fst";
+    license = with licenses; [ unlicense /* or */ mit ];
+    maintainers = with maintainers; [ rmcgibbo ];
+  };
+}
diff --git a/pkgs/tools/text/gawk/default.nix b/pkgs/tools/text/gawk/default.nix
new file mode 100644
index 00000000000..3f91a301fd1
--- /dev/null
+++ b/pkgs/tools/text/gawk/default.nix
@@ -0,0 +1,77 @@
+{ lib, stdenv, fetchurl
+# TODO: links -lsigsegv but loses the reference for some reason
+, withSigsegv ? (false && stdenv.hostPlatform.system != "x86_64-cygwin"), libsigsegv
+, interactive ? false, readline
+
+/* Test suite broke on:
+       stdenv.isCygwin # XXX: `test-dup2' segfaults on Cygwin 6.1
+    || stdenv.isDarwin # XXX: `locale' segfaults
+    || stdenv.isSunOS  # XXX: `_backsmalls1' fails, locale stuff?
+    || stdenv.isFreeBSD
+*/
+, doCheck ? (interactive && stdenv.isLinux), glibcLocales ? null
+, locale ? null
+}:
+
+assert (doCheck && stdenv.isLinux) -> glibcLocales != null;
+
+stdenv.mkDerivation rec {
+  pname = "gawk" + lib.optionalString interactive "-interactive";
+  version = "5.1.1";
+
+  src = fetchurl {
+    url = "mirror://gnu/gawk/gawk-${version}.tar.xz";
+    sha256 = "18kybw47fb1sdagav7aj95r9pp09r5gm202y3ahvwjw9dqw2jxnq";
+  };
+
+  # When we do build separate interactive version, it makes sense to always include man.
+  outputs = [ "out" "info" ]
+    ++ lib.optional (!interactive) "man";
+
+  nativeBuildInputs = lib.optional (doCheck && stdenv.isLinux) glibcLocales;
+
+  buildInputs = lib.optional withSigsegv libsigsegv
+    ++ lib.optional interactive readline
+    ++ lib.optional stdenv.isDarwin locale;
+
+  configureFlags = [
+    (if withSigsegv then "--with-libsigsegv-prefix=${libsigsegv}" else "--without-libsigsegv")
+    (if interactive then "--with-readline=${readline.dev}" else "--without-readline")
+  ];
+
+  makeFlags = [
+    "AR=${stdenv.cc.targetPrefix}ar"
+  ];
+
+  inherit doCheck;
+
+  postInstall = ''
+    rm "$out"/bin/gawk-*
+    ln -s gawk.1 "''${!outputMan}"/share/man/man1/awk.1
+  '';
+
+  passthru = {
+    libsigsegv = if withSigsegv then libsigsegv else null; # for stdenv bootstrap
+  };
+
+  meta = with lib; {
+    homepage = "https://www.gnu.org/software/gawk/";
+    description = "GNU implementation of the Awk programming language";
+    longDescription = ''
+      Many computer users need to manipulate text files: extract and then
+      operate on data from parts of certain lines while discarding the rest,
+      make changes in various text files wherever certain patterns appear,
+      and so on.  To write a program to do these things in a language such as
+      C or Pascal is a time-consuming inconvenience that may take many lines
+      of code.  The job is easy with awk, especially the GNU implementation:
+      Gawk.
+
+      The awk utility interprets a special-purpose programming language that
+      makes it possible to handle many data-reformatting jobs with just a few
+      lines of code.
+    '';
+    license = licenses.gpl3Plus;
+    platforms = platforms.unix ++ platforms.windows;
+    maintainers = [ ];
+  };
+}
diff --git a/pkgs/tools/text/gawk/gawk-with-extensions.nix b/pkgs/tools/text/gawk/gawk-with-extensions.nix
new file mode 100644
index 00000000000..1b82d798d33
--- /dev/null
+++ b/pkgs/tools/text/gawk/gawk-with-extensions.nix
@@ -0,0 +1,13 @@
+{ runCommand, gawk, extensions, makeWrapper }:
+
+runCommand "gawk-with-extensions" {
+  nativeBuildInputs = [ makeWrapper ];
+  buildInputs = [ gawk ] ++ extensions;
+} ''
+  mkdir -p $out/bin
+  for i in ${gawk}/bin/*; do
+    name="$(basename "$i")"
+    makeWrapper $i $out/bin/$name \
+      --prefix AWKLIBPATH : "${gawk}/lib/gawk:''${AWKLIBPATH:-}"
+  done
+''
diff --git a/pkgs/tools/text/gawk/gawkextlib.nix b/pkgs/tools/text/gawk/gawkextlib.nix
new file mode 100644
index 00000000000..1d3f14ea336
--- /dev/null
+++ b/pkgs/tools/text/gawk/gawkextlib.nix
@@ -0,0 +1,149 @@
+{ lib, stdenv, recurseIntoAttrs, fetchgit, writeText, pkg-config, autoreconfHook
+, autoconf, automake, libiconv, libtool, texinfo, gettext, gawk, rapidjson, gd
+, shapelib, libharu, lmdb, gmp, glibcLocales, mpfr, more, postgresql, hiredis
+, expat, tre, makeWrapper }:
+
+let
+  buildExtension = lib.makeOverridable
+    ({ name, gawkextlib, extraBuildInputs ? [ ], doCheck ? true }:
+      let is_extension = !isNull gawkextlib;
+      in stdenv.mkDerivation rec {
+        pname = "gawkextlib-${name}";
+        version = "unstable-2019-11-21";
+
+        src = fetchgit {
+          url = "git://git.code.sf.net/p/gawkextlib/code";
+          rev = "f70f10da2804e4fd0a0bac57736e9c1cf21e345d";
+          sha256 = "0r8fz89n3l4dfszs1980yqj0ah95430lj0y1lb7blfkwxa6c2xik";
+        };
+
+        postPatch = ''
+          cd ${name}
+        '';
+
+        nativeBuildInputs = [
+          autoconf
+          automake
+          libtool
+          autoreconfHook
+          pkg-config
+          texinfo
+          gettext
+        ];
+
+        buildInputs = [ gawk ] ++ extraBuildInputs;
+        propagatedBuildInputs = lib.optional is_extension gawkextlib;
+
+        setupHook = if is_extension then ./setup-hook.sh else null;
+        inherit gawk;
+
+        inherit doCheck;
+        checkInputs = [ more ];
+
+        meta = with lib; {
+          homepage = "https://sourceforge.net/projects/gawkextlib/";
+          description = "Dynamically loaded extension libraries for GNU AWK";
+          longDescription = ''
+            The gawkextlib project provides several extension libraries for
+            gawk (GNU AWK), as well as libgawkextlib containing some APIs that
+            are useful for building gawk extension libraries. These libraries
+            enable gawk to process XML data, interact with a PostgreSQL
+            database, use the GD graphics library, and perform unlimited
+            precision MPFR calculations.
+          '';
+          license = licenses.gpl3Plus;
+          platforms = platforms.unix;
+          maintainers = with maintainers; [ tomberek ];
+        };
+      });
+  gawkextlib = buildExtension {
+    gawkextlib = null;
+    name = "lib";
+  };
+  libs = {
+    abort = buildExtension {
+      inherit gawkextlib;
+      name = "abort";
+    };
+    aregex = buildExtension {
+      inherit gawkextlib;
+      name = "aregex";
+      extraBuildInputs = [ tre ];
+    };
+    csv = buildExtension {
+      inherit gawkextlib;
+      name = "csv";
+    };
+    errno = buildExtension {
+      inherit gawkextlib;
+      name = "errno";
+    };
+    gd = buildExtension {
+      inherit gawkextlib;
+      name = "gd";
+      extraBuildInputs = [ gd ];
+    };
+    haru = buildExtension {
+      inherit gawkextlib;
+      name = "haru";
+      extraBuildInputs = [ libharu ];
+    };
+    json = buildExtension {
+      inherit gawkextlib;
+      name = "json";
+      extraBuildInputs = [ rapidjson ];
+    };
+    lmdb = buildExtension {
+      inherit gawkextlib;
+      name = "lmdb";
+      extraBuildInputs = [ lmdb ];
+      #  mdb_env_open(env, /dev/null)
+      #! No such device
+      #  mdb_env_open(env, /dev/null)
+      #! Operation not supported by device
+      doCheck = !stdenv.isDarwin;
+    };
+    mbs = buildExtension {
+      inherit gawkextlib;
+      name = "mbs";
+      extraBuildInputs = [ glibcLocales ];
+      #! "spät": length: 5, mbs_length: 6, wcswidth: 4
+      doCheck = !stdenv.isDarwin;
+    };
+    mpfr = buildExtension {
+      inherit gawkextlib;
+      name = "mpfr";
+      extraBuildInputs = [ gmp mpfr ];
+    };
+    nl_langinfo = buildExtension {
+      inherit gawkextlib;
+      name = "nl_langinfo";
+    };
+    pgsql = buildExtension {
+      inherit gawkextlib;
+      name = "pgsql";
+      extraBuildInputs = [ postgresql ];
+    };
+    redis = buildExtension {
+      inherit gawkextlib;
+      name = "redis";
+      extraBuildInputs = [ hiredis ];
+    };
+    select = buildExtension {
+      inherit gawkextlib;
+      name = "select";
+    };
+    timex = buildExtension {
+      inherit gawkextlib;
+      name = "timex";
+    };
+    xml = buildExtension {
+      inherit gawkextlib;
+      name = "xml";
+      extraBuildInputs = [ expat libiconv ];
+    };
+  };
+in recurseIntoAttrs (libs // {
+  inherit gawkextlib buildExtension;
+  full = builtins.attrValues libs;
+})
diff --git a/pkgs/tools/text/gawk/setup-hook.sh b/pkgs/tools/text/gawk/setup-hook.sh
new file mode 100644
index 00000000000..d568cb8c7dd
--- /dev/null
+++ b/pkgs/tools/text/gawk/setup-hook.sh
@@ -0,0 +1,6 @@
+local oldOpts="-u"
+shopt -qo nounset || oldOpts="+u"
+set +u
+. @gawk@/etc/profile.d/gawk.sh
+gawklibpath_append @out@/lib/gawk
+set "$oldOpts"
diff --git a/pkgs/tools/text/gist/default.nix b/pkgs/tools/text/gist/default.nix
new file mode 100644
index 00000000000..d2676b37997
--- /dev/null
+++ b/pkgs/tools/text/gist/default.nix
@@ -0,0 +1,17 @@
+{ buildRubyGem, lib, ruby }:
+
+buildRubyGem rec {
+  inherit ruby;
+  name = "${gemName}-${version}";
+  gemName = "gist";
+  version = "6.0.0";
+  source.sha256 = "0qnd1jqd7b04871v4l73grcmi7c0pivm8nsfrqvwivm4n4b3c2hd";
+
+  meta = with lib; {
+    description = "Upload code to https://gist.github.com (or github enterprise)";
+    homepage = "http://defunkt.io/gist/";
+    license = licenses.mit;
+    maintainers = with maintainers; [ zimbatm ];
+    platforms = ruby.meta.platforms;
+  };
+}
diff --git a/pkgs/tools/text/gjo/default.nix b/pkgs/tools/text/gjo/default.nix
new file mode 100644
index 00000000000..da8fa212940
--- /dev/null
+++ b/pkgs/tools/text/gjo/default.nix
@@ -0,0 +1,25 @@
+{ lib
+, buildGoModule
+, fetchFromGitHub
+}:
+
+buildGoModule rec {
+  pname = "gjo";
+  version = "1.0.3";
+
+  src = fetchFromGitHub {
+    owner = "skanehira";
+    repo = "gjo";
+    rev = version;
+    sha256 = "07halr0jzds4rya6hlvp45bjf7vg4yf49w5q60mch05hk8qkjjdw";
+  };
+
+  vendorSha256 = null;
+
+  meta = with lib; {
+    description = "Small utility to create JSON objects";
+    homepage = "https://github.com/skanehira/gjo";
+    license = licenses.mit;
+    maintainers = with maintainers; [ doronbehar ];
+  };
+}
diff --git a/pkgs/tools/text/glogg/default.nix b/pkgs/tools/text/glogg/default.nix
new file mode 100644
index 00000000000..855490df4ab
--- /dev/null
+++ b/pkgs/tools/text/glogg/default.nix
@@ -0,0 +1,40 @@
+{ mkDerivation, lib, stdenv, fetchFromGitHub, qmake, boost }:
+
+mkDerivation rec {
+  pname = "glogg";
+  version = "1.1.4";
+
+  src = fetchFromGitHub {
+    owner = "nickbnf";
+    repo = "glogg";
+    rev = "v${version}";
+    sha256 = "0hf1c2m8n88frmxmyn0ndr8129p7iky49nq565sw1asaydm5z6pb";
+  };
+
+  postPatch = lib.optionalString stdenv.isDarwin ''
+    substituteInPlace glogg.pro \
+      --replace "boost_program_options-mt" "boost_program_options"
+  '';
+
+  nativeBuildInputs = [ qmake ];
+  buildInputs = [ boost ];
+
+  qmakeFlags = [ "VERSION=${version}" ];
+
+  postInstall = lib.optionalString stdenv.isDarwin ''
+    mkdir -p $out/Applications
+    mv $out/bin/glogg.app $out/Applications/glogg.app
+    rm -fr $out/{bin,share}
+  '';
+
+  meta = with lib; {
+    description = "The fast, smart log explorer";
+    longDescription = ''
+      A multi-platform GUI application to browse and search through long or complex log files. It is designed with programmers and system administrators in mind. glogg can be seen as a graphical, interactive combination of grep and less.
+    '';
+    homepage = "https://glogg.bonnefon.org/";
+    license = licenses.gpl3Plus;
+    platforms = platforms.unix;
+    maintainers = with maintainers; [ c0bw3b ];
+  };
+}
diff --git a/pkgs/tools/text/gnugrep/default.nix b/pkgs/tools/text/gnugrep/default.nix
new file mode 100644
index 00000000000..efb3be1c8fb
--- /dev/null
+++ b/pkgs/tools/text/gnugrep/default.nix
@@ -0,0 +1,70 @@
+{ lib, stdenv, fetchurl, pcre, libiconv, perl }:
+
+# Note: this package is used for bootstrapping fetchurl, and thus
+# cannot use fetchpatch! All mutable patches (generated by GitHub or
+# cgit) that are needed here should be included directly in Nixpkgs as
+# files.
+
+let version = "3.7"; in
+
+stdenv.mkDerivation {
+  pname = "gnugrep";
+  inherit version;
+
+  src = fetchurl {
+    url = "mirror://gnu/grep/grep-${version}.tar.xz";
+    sha256 = "0g42svbc1nq5bamxfj6x7320wli4dlj86padk0hwgbk04hqxl42w";
+  };
+
+  # Perl is needed for testing
+  nativeBuildInputs = [ perl ];
+  outputs = [ "out" "info" ]; # the man pages are rather small
+
+  buildInputs = [ pcre libiconv ];
+
+  # cygwin: FAIL: multibyte-white-space
+  # freebsd: FAIL mb-non-UTF8-performance
+  # all platforms: timing sensitivity in long-pattern-perf
+  #doCheck = !stdenv.isDarwin && !stdenv.isSunOS && !stdenv.isCygwin && !stdenv.isFreeBSD;
+  doCheck = false;
+
+  # On macOS, force use of mkdir -p, since Grep's fallback
+  # (./install-sh) is broken.
+  preConfigure = ''
+    export MKDIR_P="mkdir -p"
+  '';
+
+  # Fix reference to sh in bootstrap-tools, and invoke grep via
+  # absolute path rather than looking at argv[0].
+  postInstall =
+    ''
+      rm $out/bin/egrep $out/bin/fgrep
+      echo "#! /bin/sh" > $out/bin/egrep
+      echo "exec $out/bin/grep -E \"\$@\"" >> $out/bin/egrep
+      echo "#! /bin/sh" > $out/bin/fgrep
+      echo "exec $out/bin/grep -F \"\$@\"" >> $out/bin/fgrep
+      chmod +x $out/bin/egrep $out/bin/fgrep
+    '';
+
+  meta = with lib; {
+    homepage = "https://www.gnu.org/software/grep/";
+    description = "GNU implementation of the Unix grep command";
+
+    longDescription = ''
+      The grep command searches one or more input files for lines
+      containing a match to a specified pattern.  By default, grep
+      prints the matching lines.
+    '';
+
+    license = licenses.gpl3Plus;
+
+    maintainers = [
+      maintainers.eelco
+      maintainers.m00wl
+    ];
+    platforms = platforms.all;
+    mainProgram = "grep";
+  };
+
+  passthru = {inherit pcre;};
+}
diff --git a/pkgs/tools/text/gnupatch/Allow_input_files_to_be_missing_for_ed-style_patches.patch b/pkgs/tools/text/gnupatch/Allow_input_files_to_be_missing_for_ed-style_patches.patch
new file mode 100644
index 00000000000..98c9aa877a7
--- /dev/null
+++ b/pkgs/tools/text/gnupatch/Allow_input_files_to_be_missing_for_ed-style_patches.patch
@@ -0,0 +1,33 @@
+From b5a91a01e5d0897facdd0f49d64b76b0f02b43e1 Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruen@gnu.org>
+Date: Fri, 6 Apr 2018 11:34:51 +0200
+Subject: Allow input files to be missing for ed-style patches
+
+* src/pch.c (do_ed_script): Allow input files to be missing so that new
+files will be created as with non-ed-style patches.
+---
+ src/pch.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/src/pch.c b/src/pch.c
+index bc6278c..0c5cc26 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2394,9 +2394,11 @@ do_ed_script (char const *inname, char const *outname,
+ 
+     if (! dry_run && ! skip_rest_of_patch) {
+ 	int exclusive = *outname_needs_removal ? 0 : O_EXCL;
+-	assert (! inerrno);
+-	*outname_needs_removal = true;
+-	copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
++	if (inerrno != ENOENT)
++	  {
++	    *outname_needs_removal = true;
++	    copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
++	  }
+ 	sprintf (buf, "%s %s%s", editor_program,
+ 		 verbosity == VERBOSE ? "" : "- ",
+ 		 outname);
+-- 
+cgit v1.0-41-gc330
+
diff --git a/pkgs/tools/text/gnupatch/CVE-2018-1000156.patch b/pkgs/tools/text/gnupatch/CVE-2018-1000156.patch
new file mode 100644
index 00000000000..36f33dea2b9
--- /dev/null
+++ b/pkgs/tools/text/gnupatch/CVE-2018-1000156.patch
@@ -0,0 +1,211 @@
+From 123eaff0d5d1aebe128295959435b9ca5909c26d Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruen@gnu.org>
+Date: Fri, 6 Apr 2018 12:14:49 +0200
+Subject: Fix arbitrary command execution in ed-style patches
+ (CVE-2018-1000156)
+
+* src/pch.c (do_ed_script): Write ed script to a temporary file instead
+of piping it to ed: this will cause ed to abort on invalid commands
+instead of rejecting them and carrying on.
+* tests/ed-style: New test case.
+* tests/Makefile.am (TESTS): Add test case.
+---
+ src/pch.c         | 91 ++++++++++++++++++++++++++++++++++++++++---------------
+ tests/Makefile.am |  1 +
+ tests/ed-style    | 41 +++++++++++++++++++++++++
+ 3 files changed, 108 insertions(+), 25 deletions(-)
+ create mode 100644 tests/ed-style
+
+diff --git a/src/pch.c b/src/pch.c
+index 0c5cc26..4fd5a05 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -33,6 +33,7 @@
+ # include <io.h>
+ #endif
+ #include <safe.h>
++#include <sys/wait.h>
+ 
+ #define INITHUNKMAX 125			/* initial dynamic allocation size */
+ 
+@@ -2389,24 +2390,28 @@ do_ed_script (char const *inname, char const *outname,
+     static char const editor_program[] = EDITOR_PROGRAM;
+ 
+     file_offset beginning_of_this_line;
+-    FILE *pipefp = 0;
+     size_t chars_read;
++    FILE *tmpfp = 0;
++    char const *tmpname;
++    int tmpfd;
++    pid_t pid;
++
++    if (! dry_run && ! skip_rest_of_patch)
++      {
++	/* Write ed script to a temporary file.  This causes ed to abort on
++	   invalid commands such as when line numbers or ranges exceed the
++	   number of available lines.  When ed reads from a pipe, it rejects
++	   invalid commands and treats the next line as a new command, which
++	   can lead to arbitrary command execution.  */
++
++	tmpfd = make_tempfile (&tmpname, 'e', NULL, O_RDWR | O_BINARY, 0);
++	if (tmpfd == -1)
++	  pfatal ("Can't create temporary file %s", quotearg (tmpname));
++	tmpfp = fdopen (tmpfd, "w+b");
++	if (! tmpfp)
++	  pfatal ("Can't open stream for file %s", quotearg (tmpname));
++      }
+ 
+-    if (! dry_run && ! skip_rest_of_patch) {
+-	int exclusive = *outname_needs_removal ? 0 : O_EXCL;
+-	if (inerrno != ENOENT)
+-	  {
+-	    *outname_needs_removal = true;
+-	    copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
+-	  }
+-	sprintf (buf, "%s %s%s", editor_program,
+-		 verbosity == VERBOSE ? "" : "- ",
+-		 outname);
+-	fflush (stdout);
+-	pipefp = popen(buf, binary_transput ? "wb" : "w");
+-	if (!pipefp)
+-	  pfatal ("Can't open pipe to %s", quotearg (buf));
+-    }
+     for (;;) {
+ 	char ed_command_letter;
+ 	beginning_of_this_line = file_tell (pfp);
+@@ -2417,14 +2422,14 @@ do_ed_script (char const *inname, char const *outname,
+ 	}
+ 	ed_command_letter = get_ed_command_letter (buf);
+ 	if (ed_command_letter) {
+-	    if (pipefp)
+-		if (! fwrite (buf, sizeof *buf, chars_read, pipefp))
++	    if (tmpfp)
++		if (! fwrite (buf, sizeof *buf, chars_read, tmpfp))
+ 		    write_fatal ();
+ 	    if (ed_command_letter != 'd' && ed_command_letter != 's') {
+ 	        p_pass_comments_through = true;
+ 		while ((chars_read = get_line ()) != 0) {
+-		    if (pipefp)
+-			if (! fwrite (buf, sizeof *buf, chars_read, pipefp))
++		    if (tmpfp)
++			if (! fwrite (buf, sizeof *buf, chars_read, tmpfp))
+ 			    write_fatal ();
+ 		    if (chars_read == 2  &&  strEQ (buf, ".\n"))
+ 			break;
+@@ -2437,13 +2442,49 @@ do_ed_script (char const *inname, char const *outname,
+ 	    break;
+ 	}
+     }
+-    if (!pipefp)
++    if (!tmpfp)
+       return;
+-    if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, pipefp) == 0
+-	|| fflush (pipefp) != 0)
++    if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) == 0
++	|| fflush (tmpfp) != 0)
+       write_fatal ();
+-    if (pclose (pipefp) != 0)
+-      fatal ("%s FAILED", editor_program);
++
++    if (lseek (tmpfd, 0, SEEK_SET) == -1)
++      pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname));
++
++    if (! dry_run && ! skip_rest_of_patch) {
++	int exclusive = *outname_needs_removal ? 0 : O_EXCL;
++	*outname_needs_removal = true;
++	if (inerrno != ENOENT)
++	  {
++	    *outname_needs_removal = true;
++	    copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
++	  }
++	sprintf (buf, "%s %s%s", editor_program,
++		 verbosity == VERBOSE ? "" : "- ",
++		 outname);
++	fflush (stdout);
++
++	pid = fork();
++	if (pid == -1)
++	  pfatal ("Can't fork");
++	else if (pid == 0)
++	  {
++	    dup2 (tmpfd, 0);
++	    execl ("/bin/sh", "sh", "-c", buf, (char *) 0);
++	    _exit (2);
++	  }
++	else
++	  {
++	    int wstatus;
++	    if (waitpid (pid, &wstatus, 0) == -1
++	        || ! WIFEXITED (wstatus)
++		|| WEXITSTATUS (wstatus) != 0)
++	      fatal ("%s FAILED", editor_program);
++	  }
++    }
++
++    fclose (tmpfp);
++    safe_unlink (tmpname);
+ 
+     if (ofp)
+       {
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 6b6df63..16f8693 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -32,6 +32,7 @@ TESTS = \
+ 	crlf-handling \
+ 	dash-o-append \
+ 	deep-directories \
++	ed-style \
+ 	empty-files \
+ 	false-match \
+ 	fifo \
+diff --git a/tests/ed-style b/tests/ed-style
+new file mode 100644
+index 0000000..d8c0689
+--- /dev/null
++++ b/tests/ed-style
+@@ -0,0 +1,41 @@
++# Copyright (C) 2018 Free Software Foundation, Inc.
++#
++# Copying and distribution of this file, with or without modification,
++# in any medium, are permitted without royalty provided the copyright
++# notice and this notice are preserved.
++
++. $srcdir/test-lib.sh
++
++require cat
++use_local_patch
++use_tmpdir
++
++# ==============================================================
++
++cat > ed1.diff <<EOF
++0a
++foo
++.
++EOF
++
++check 'patch -e foo -i ed1.diff' <<EOF
++EOF
++
++check 'cat foo' <<EOF
++foo
++EOF
++
++cat > ed2.diff <<EOF
++1337a
++r !echo bar
++,p
++EOF
++
++check 'patch -e foo -i ed2.diff 2> /dev/null || echo "Status: $?"' <<EOF
++?
++Status: 2
++EOF
++
++check 'cat foo' <<EOF
++foo
++EOF
+-- 
+cgit v1.0-41-gc330
+
diff --git a/pkgs/tools/text/gnupatch/CVE-2018-6951.patch b/pkgs/tools/text/gnupatch/CVE-2018-6951.patch
new file mode 100644
index 00000000000..22d5f061c33
--- /dev/null
+++ b/pkgs/tools/text/gnupatch/CVE-2018-6951.patch
@@ -0,0 +1,28 @@
+From f290f48a621867084884bfff87f8093c15195e6a Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruen@gnu.org>
+Date: Mon, 12 Feb 2018 16:48:24 +0100
+Subject: Fix segfault with mangled rename patch
+
+http://savannah.gnu.org/bugs/?53132
+* src/pch.c (intuit_diff_type): Ensure that two filenames are specified
+for renames and copies (fix the existing check).
+---
+ src/pch.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/pch.c b/src/pch.c
+index ff9ed2c..bc6278c 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -974,7 +974,8 @@ intuit_diff_type (bool need_header, mode_t *p_file_type)
+     if ((pch_rename () || pch_copy ())
+ 	&& ! inname
+ 	&& ! ((i == OLD || i == NEW) &&
+-	      p_name[! reverse] &&
++	      p_name[reverse] && p_name[! reverse] &&
++	      name_is_valid (p_name[reverse]) &&
+ 	      name_is_valid (p_name[! reverse])))
+       {
+ 	say ("Cannot %s file without two valid file names\n", pch_rename () ? "rename" : "copy");
+-- 
+cgit v1.0-41-gc330
diff --git a/pkgs/tools/text/gnupatch/CVE-2018-6952.patch b/pkgs/tools/text/gnupatch/CVE-2018-6952.patch
new file mode 100644
index 00000000000..2da323c6984
--- /dev/null
+++ b/pkgs/tools/text/gnupatch/CVE-2018-6952.patch
@@ -0,0 +1,28 @@
+From 9c986353e420ead6e706262bf204d6e03322c300 Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruen@gnu.org>
+Date: Fri, 17 Aug 2018 13:35:40 +0200
+Subject: Fix swapping fake lines in pch_swap
+
+* src/pch.c (pch_swap): Fix swapping p_bfake and p_efake when there is a
+blank line in the middle of a context-diff hunk: that empty line stays
+in the middle of the hunk and isn't swapped.
+
+Fixes: https://savannah.gnu.org/bugs/index.php?53133
+---
+ src/pch.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/pch.c b/src/pch.c
+index e92bc64..a500ad9 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2122,7 +2122,7 @@ pch_swap (void)
+     }
+     if (p_efake >= 0) {			/* fix non-freeable ptr range */
+ 	if (p_efake <= i)
+-	    n = p_end - i + 1;
++	    n = p_end - p_ptrn_lines;
+ 	else
+ 	    n = -i;
+ 	p_efake += n;
+-- 
diff --git a/pkgs/tools/text/gnupatch/CVE-2019-13636.patch b/pkgs/tools/text/gnupatch/CVE-2019-13636.patch
new file mode 100644
index 00000000000..e62c3d41753
--- /dev/null
+++ b/pkgs/tools/text/gnupatch/CVE-2019-13636.patch
@@ -0,0 +1,108 @@
+From dce4683cbbe107a95f1f0d45fabc304acfb5d71a Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruen@gnu.org>
+Date: Mon, 15 Jul 2019 16:21:48 +0200
+Subject: Don't follow symlinks unless --follow-symlinks is given
+
+* src/inp.c (plan_a, plan_b), src/util.c (copy_to_fd, copy_file,
+append_to_file): Unless the --follow-symlinks option is given, open files with
+the O_NOFOLLOW flag to avoid following symlinks.  So far, we were only doing
+that consistently for input files.
+* src/util.c (create_backup): When creating empty backup files, (re)create them
+with O_CREAT | O_EXCL to avoid following symlinks in that case as well.
+---
+ src/inp.c  | 12 ++++++++++--
+ src/util.c | 14 +++++++++++---
+ 2 files changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/src/inp.c b/src/inp.c
+index 32d0919..22d7473 100644
+--- a/src/inp.c
++++ b/src/inp.c
+@@ -238,8 +238,13 @@ plan_a (char const *filename)
+     {
+       if (S_ISREG (instat.st_mode))
+         {
+-	  int ifd = safe_open (filename, O_RDONLY|binary_transput, 0);
++	  int flags = O_RDONLY | binary_transput;
+ 	  size_t buffered = 0, n;
++	  int ifd;
++
++	  if (! follow_symlinks)
++	    flags |= O_NOFOLLOW;
++	  ifd = safe_open (filename, flags, 0);
+ 	  if (ifd < 0)
+ 	    pfatal ("can't open file %s", quotearg (filename));
+ 
+@@ -340,6 +345,7 @@ plan_a (char const *filename)
+ static void
+ plan_b (char const *filename)
+ {
++  int flags = O_RDONLY | binary_transput;
+   int ifd;
+   FILE *ifp;
+   int c;
+@@ -353,7 +359,9 @@ plan_b (char const *filename)
+ 
+   if (instat.st_size == 0)
+     filename = NULL_DEVICE;
+-  if ((ifd = safe_open (filename, O_RDONLY | binary_transput, 0)) < 0
++  if (! follow_symlinks)
++    flags |= O_NOFOLLOW;
++  if ((ifd = safe_open (filename, flags, 0)) < 0
+       || ! (ifp = fdopen (ifd, binary_transput ? "rb" : "r")))
+     pfatal ("Can't open file %s", quotearg (filename));
+   if (TMPINNAME_needs_removal)
+diff --git a/src/util.c b/src/util.c
+index 1cc08ba..fb38307 100644
+--- a/src/util.c
++++ b/src/util.c
+@@ -388,7 +388,7 @@ create_backup (char const *to, const struct stat *to_st, bool leave_original)
+ 
+ 	  try_makedirs_errno = ENOENT;
+ 	  safe_unlink (bakname);
+-	  while ((fd = safe_open (bakname, O_CREAT | O_WRONLY | O_TRUNC, 0666)) < 0)
++	  while ((fd = safe_open (bakname, O_CREAT | O_EXCL | O_WRONLY | O_TRUNC, 0666)) < 0)
+ 	    {
+ 	      if (errno != try_makedirs_errno)
+ 		pfatal ("Can't create file %s", quotearg (bakname));
+@@ -579,10 +579,13 @@ create_file (char const *file, int open_flags, mode_t mode,
+ static void
+ copy_to_fd (const char *from, int tofd)
+ {
++  int from_flags = O_RDONLY | O_BINARY;
+   int fromfd;
+   ssize_t i;
+ 
+-  if ((fromfd = safe_open (from, O_RDONLY | O_BINARY, 0)) < 0)
++  if (! follow_symlinks)
++    from_flags |= O_NOFOLLOW;
++  if ((fromfd = safe_open (from, from_flags, 0)) < 0)
+     pfatal ("Can't reopen file %s", quotearg (from));
+   while ((i = read (fromfd, buf, bufsize)) != 0)
+     {
+@@ -625,6 +628,8 @@ copy_file (char const *from, char const *to, struct stat *tost,
+   else
+     {
+       assert (S_ISREG (mode));
++      if (! follow_symlinks)
++	to_flags |= O_NOFOLLOW;
+       tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode,
+ 			  to_dir_known_to_exist);
+       copy_to_fd (from, tofd);
+@@ -640,9 +645,12 @@ copy_file (char const *from, char const *to, struct stat *tost,
+ void
+ append_to_file (char const *from, char const *to)
+ {
++  int to_flags = O_WRONLY | O_APPEND | O_BINARY;
+   int tofd;
+ 
+-  if ((tofd = safe_open (to, O_WRONLY | O_BINARY | O_APPEND, 0)) < 0)
++  if (! follow_symlinks)
++    to_flags |= O_NOFOLLOW;
++  if ((tofd = safe_open (to, to_flags, 0)) < 0)
+     pfatal ("Can't reopen file %s", quotearg (to));
+   copy_to_fd (from, tofd);
+   if (close (tofd) != 0)
+-- 
+cgit v1.0-41-gc330
+
diff --git a/pkgs/tools/text/gnupatch/CVE-2019-13638-and-CVE-2018-20969.patch b/pkgs/tools/text/gnupatch/CVE-2019-13638-and-CVE-2018-20969.patch
new file mode 100644
index 00000000000..38caff628aa
--- /dev/null
+++ b/pkgs/tools/text/gnupatch/CVE-2019-13638-and-CVE-2018-20969.patch
@@ -0,0 +1,38 @@
+From 3fcd042d26d70856e826a42b5f93dc4854d80bf0 Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruen@gnu.org>
+Date: Fri, 6 Apr 2018 19:36:15 +0200
+Subject: Invoke ed directly instead of using the shell
+
+* src/pch.c (do_ed_script): Invoke ed directly instead of using a shell
+command to avoid quoting vulnerabilities.
+---
+ src/pch.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/src/pch.c b/src/pch.c
+index 4fd5a05..16e001a 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2459,9 +2459,6 @@ do_ed_script (char const *inname, char const *outname,
+ 	    *outname_needs_removal = true;
+ 	    copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
+ 	  }
+-	sprintf (buf, "%s %s%s", editor_program,
+-		 verbosity == VERBOSE ? "" : "- ",
+-		 outname);
+ 	fflush (stdout);
+ 
+ 	pid = fork();
+@@ -2470,7 +2467,8 @@ do_ed_script (char const *inname, char const *outname,
+ 	else if (pid == 0)
+ 	  {
+ 	    dup2 (tmpfd, 0);
+-	    execl ("/bin/sh", "sh", "-c", buf, (char *) 0);
++	    assert (outname[0] != '!' && outname[0] != '-');
++	    execlp (editor_program, editor_program, "-", outname, (char  *) NULL);
+ 	    _exit (2);
+ 	  }
+ 	else
+-- 
+cgit v1.0-41-gc330
+
diff --git a/pkgs/tools/text/gnupatch/default.nix b/pkgs/tools/text/gnupatch/default.nix
new file mode 100644
index 00000000000..8d8fa7d0a8b
--- /dev/null
+++ b/pkgs/tools/text/gnupatch/default.nix
@@ -0,0 +1,59 @@
+{ lib, stdenv, fetchurl
+, ed, autoreconfHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "patch";
+  version = "2.7.6";
+
+  src = fetchurl {
+    url = "mirror://gnu/patch/patch-${version}.tar.xz";
+    sha256 = "1zfqy4rdcy279vwn2z1kbv19dcfw25d2aqy9nzvdkq5bjzd0nqdc";
+  };
+
+  patches = [
+    # https://git.savannah.gnu.org/cgit/patch.git/patch/?id=f290f48a621867084884bfff87f8093c15195e6a
+    ./CVE-2018-6951.patch
+
+    # https://git.savannah.gnu.org/cgit/patch.git/patch/?id=b5a91a01e5d0897facdd0f49d64b76b0f02b43e1
+    ./Allow_input_files_to_be_missing_for_ed-style_patches.patch
+
+    # https://git.savannah.gnu.org/cgit/patch.git/patch/?id=123eaff0d5d1aebe128295959435b9ca5909c26d
+    ./CVE-2018-1000156.patch
+
+    # https://git.savannah.gnu.org/cgit/patch.git/commit/?id=9c986353e420ead6e706262bf204d6e03322c300
+    ./CVE-2018-6952.patch
+
+    # https://git.savannah.gnu.org/cgit/patch.git/patch/?id=dce4683cbbe107a95f1f0d45fabc304acfb5d71a
+    ./CVE-2019-13636.patch
+
+    # https://git.savannah.gnu.org/cgit/patch.git/patch/?id=3fcd042d26d70856e826a42b5f93dc4854d80bf0
+    ./CVE-2019-13638-and-CVE-2018-20969.patch
+  ];
+
+  nativeBuildInputs = [ autoreconfHook ];
+
+  configureFlags = lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
+    "ac_cv_func_strnlen_working=yes"
+  ];
+
+  doCheck = stdenv.hostPlatform.libc != "musl"; # not cross;
+  checkInputs = [ed];
+
+  meta = {
+    description = "GNU Patch, a program to apply differences to files";
+
+    longDescription =
+      '' GNU Patch takes a patch file containing a difference listing
+         produced by the diff program and applies those differences to one or
+         more original files, producing patched versions.
+      '';
+
+    homepage = "https://savannah.gnu.org/projects/patch";
+
+    license = lib.licenses.gpl3Plus;
+
+    maintainers = [ ];
+    platforms = lib.platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/gnused/422.nix b/pkgs/tools/text/gnused/422.nix
new file mode 100644
index 00000000000..15e57e31901
--- /dev/null
+++ b/pkgs/tools/text/gnused/422.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "gnused";
+  version = "4.2.2";
+
+  src = fetchurl {
+    url = "mirror://gnu/sed/sed-${version}.tar.bz2";
+    sha256 = "f048d1838da284c8bc9753e4506b85a1e0cc1ea8999d36f6995bcb9460cddbd7";
+  };
+
+  configureFlags = lib.optional stdenv.hostPlatform.isMinGW "ac_cv_func__set_invalid_parameter_handler=no";
+
+  outputs = [ "out" "info" ];
+
+  meta = {
+    homepage = "https://www.gnu.org/software/sed/";
+    description = "GNU sed, a batch stream editor";
+
+    longDescription = ''
+      Sed (stream editor) isn't really a true text editor or text
+      processor.  Instead, it is used to filter text, i.e., it takes
+      text input and performs some operation (or set of operations) on
+      it and outputs the modified text.  Sed is typically used for
+      extracting part of a file using pattern matching or substituting
+      multiple occurrences of a string within a file.
+    '';
+
+    license = lib.licenses.gpl3Plus;
+
+    platforms = lib.platforms.all;
+    maintainers = [ ];
+    mainProgram = "sed";
+  };
+}
diff --git a/pkgs/tools/text/gnused/default.nix b/pkgs/tools/text/gnused/default.nix
new file mode 100644
index 00000000000..32f6f30cb1a
--- /dev/null
+++ b/pkgs/tools/text/gnused/default.nix
@@ -0,0 +1,39 @@
+{ lib, stdenv, fetchurl, perl }:
+
+stdenv.mkDerivation rec {
+  pname = "gnused";
+  version = "4.8";
+
+  src = fetchurl {
+    url = "mirror://gnu/sed/sed-${version}.tar.xz";
+    sha256 = "0cznxw73fzv1n3nj2zsq6nf73rvsbxndp444xkpahdqvlzz0r6zp";
+  };
+
+  outputs = [ "out" "info" ];
+
+  nativeBuildInputs = [ perl ];
+  preConfigure = "patchShebangs ./build-aux/help2man";
+
+  # Prevents attempts of running 'help2man' on cross-built binaries.
+  PERL = if stdenv.hostPlatform == stdenv.buildPlatform then null else "missing";
+
+  meta = {
+    homepage = "https://www.gnu.org/software/sed/";
+    description = "GNU sed, a batch stream editor";
+
+    longDescription = ''
+      Sed (stream editor) isn't really a true text editor or text
+      processor.  Instead, it is used to filter text, i.e., it takes
+      text input and performs some operation (or set of operations) on
+      it and outputs the modified text.  Sed is typically used for
+      extracting part of a file using pattern matching or substituting
+      multiple occurrences of a string within a file.
+    '';
+
+    license = lib.licenses.gpl3Plus;
+
+    platforms = lib.platforms.unix;
+    maintainers = with lib.maintainers; [ mic92 ];
+    mainProgram = "sed";
+  };
+}
diff --git a/pkgs/tools/text/goawk/default.nix b/pkgs/tools/text/goawk/default.nix
new file mode 100644
index 00000000000..b665c182332
--- /dev/null
+++ b/pkgs/tools/text/goawk/default.nix
@@ -0,0 +1,25 @@
+{ buildGoModule, fetchFromGitHub, lib }:
+buildGoModule rec {
+  pname = "goawk";
+  version = "1.16.0";
+
+  src = fetchFromGitHub {
+    owner = "benhoyt";
+    repo = "goawk";
+    rev = "v${version}";
+    sha256 = "sha256-ALzCcSZHnzidj4tQzZWXT8WDPIE147KWbn7n1JHCTRE=";
+  };
+
+  vendorSha256 = "sha256-pQpattmS9VmO3ZIQUFn66az8GSmB4IvYhTTCFn6SUmo=";
+
+  # checks do not pass at the moment
+  doCheck = false;
+
+  meta = with lib; {
+    description = "A POSIX-compliant AWK interpreter written in Go";
+    homepage = "https://benhoyt.com/writings/goawk/";
+    license = licenses.mit;
+    mainProgram = "goawk";
+    maintainers = with maintainers; [ abbe ];
+  };
+}
diff --git a/pkgs/tools/text/gpt2tc/0001-add-python-shebang.patch b/pkgs/tools/text/gpt2tc/0001-add-python-shebang.patch
new file mode 100644
index 00000000000..b47b444009a
--- /dev/null
+++ b/pkgs/tools/text/gpt2tc/0001-add-python-shebang.patch
@@ -0,0 +1,10 @@
+diff --git a/gpt2convert.py b/gpt2convert.py
+index 34ca909..6e6cac5 100644
+--- a/gpt2convert.py
++++ b/gpt2convert.py
+@@ -1,3 +1,5 @@
++#!/usr/bin/env python3
++
+ import sys
+ import tensorflow as tf
+ import numpy as np
diff --git a/pkgs/tools/text/gpt2tc/default.nix b/pkgs/tools/text/gpt2tc/default.nix
new file mode 100644
index 00000000000..4d6ac33d61d
--- /dev/null
+++ b/pkgs/tools/text/gpt2tc/default.nix
@@ -0,0 +1,44 @@
+{ lib, stdenv, fetchurl, autoPatchelfHook, python3 }:
+
+stdenv.mkDerivation rec {
+  pname = "gpt2tc";
+  version = "2021-04-24";
+
+  src = fetchurl {
+    url = "https://bellard.org/libnc/gpt2tc-${version}.tar.gz";
+    hash = "sha256-kHnRziSNRewifM/oKDQwG27rXRvntuUUX8M+PUNHpA4=";
+  };
+
+  patches = [
+    # Add a shebang to the python script so that nix detects it as such and
+    # wraps it properly. Otherwise, it runs in shell and freezes the system.
+    ./0001-add-python-shebang.patch
+  ];
+
+  nativeBuildInputs = [ autoPatchelfHook ];
+
+  buildInputs = [
+    (python3.withPackages (p: with p; [ numpy tensorflow ]))
+  ];
+
+  installPhase = ''
+    runHook preInstall
+
+    install -D -m755 -t $out/lib libnc${stdenv.hostPlatform.extensions.sharedLibrary}
+    addAutoPatchelfSearchPath $out/lib
+    install -D -m755 -t $out/bin gpt2tc
+    install -T -m755 download_model.sh $out/bin/gpt2-download-model
+    install -T -m755 gpt2convert.py $out/bin/gpt2-convert
+    install -D -m644 -t $out/share/gpt2tc readme.txt gpt2vocab.txt Changelog
+
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Text completion and compression using GPT-2";
+    homepage = "https://bellard.org/libnc/gpt2tc.html";
+    license = licenses.unfree;
+    platforms = [ "x86_64-linux" ];
+    maintainers = with maintainers; [ anna328p ];
+  };
+}
diff --git a/pkgs/tools/text/grin/default.nix b/pkgs/tools/text/grin/default.nix
new file mode 100644
index 00000000000..ffa80baf6ea
--- /dev/null
+++ b/pkgs/tools/text/grin/default.nix
@@ -0,0 +1,23 @@
+{ lib, fetchFromGitHub, python3Packages }:
+
+python3Packages.buildPythonApplication rec {
+  pname = "grin";
+  version = "1.3.0";
+  namePrefix = "";
+
+  src = fetchFromGitHub {
+    owner = "matthew-brett";
+    repo = pname;
+    rev = "1.3.0";
+    sha256 = "057d05vzx4sf415vnh3qj2g351xhb3illjxjs9mdl3nsnb5r84kv";
+  };
+
+  buildInputs = with python3Packages; [ nose ];
+
+  meta = {
+    homepage = "https://github.com/matthew-brett/grin";
+    description = "A grep program configured the way I like it";
+    platforms = lib.platforms.all;
+    maintainers = [ lib.maintainers.sjagoe ];
+  };
+}
diff --git a/pkgs/tools/text/grip-search/default.nix b/pkgs/tools/text/grip-search/default.nix
new file mode 100644
index 00000000000..57f0139dbc9
--- /dev/null
+++ b/pkgs/tools/text/grip-search/default.nix
@@ -0,0 +1,31 @@
+{ lib, stdenv, fetchFromGitHub, boost, pkg-config, cmake, catch2 }:
+
+stdenv.mkDerivation rec {
+  pname = "grip-search";
+  version = "0.8";
+
+  src = fetchFromGitHub {
+    owner = "sc0ty";
+    repo = "grip";
+    rev = "v${version}";
+    sha256 = "0bkqarylgzhis6fpj48qbifcd6a26cgnq8784hgnm707rq9kb0rx";
+  };
+
+  nativeBuildInputs = [ pkg-config cmake catch2 ];
+
+  doCheck = true;
+
+  buildInputs = [ boost ];
+
+  patchPhase = ''
+    substituteInPlace src/general/config.h --replace "CUSTOM-BUILD" "${version}"
+  '';
+
+  meta = with lib; {
+    description = "Fast, indexed regexp search over large file trees";
+    homepage = "https://github.com/sc0ty/grip";
+    license = licenses.gpl3;
+    platforms = platforms.all;
+    maintainers = with maintainers; [ tex ];
+  };
+}
diff --git a/pkgs/tools/text/groff/0001-Fix-cross-compilation-by-looking-for-ar.patch b/pkgs/tools/text/groff/0001-Fix-cross-compilation-by-looking-for-ar.patch
new file mode 100644
index 00000000000..671293cda5b
--- /dev/null
+++ b/pkgs/tools/text/groff/0001-Fix-cross-compilation-by-looking-for-ar.patch
@@ -0,0 +1,46 @@
+From 1454525f70b43a6957b7c9e1870e997368787da3 Mon Sep 17 00:00:00 2001
+From: Samuel Dionne-Riel <samuel@dionne-riel.com>
+Date: Fri, 8 Nov 2019 21:59:21 -0500
+Subject: [PATCH] Fix cross-compilation by looking for `ar`.
+
+---
+ Makefile.am  | 2 +-
+ configure.ac | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index d18c49b8..b1b53338 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -494,7 +494,7 @@ CCC=@CXX@
+ # INSTALL_INFO
+ # LN_S
+ 
+-AR=ar
++AR=@AR@
+ ETAGS=etags
+ ETAGSFLAGS=
+ # Flag that tells etags to assume C++.
+diff --git a/configure.ac b/configure.ac
+index 28e75f17..2449b9f5 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -37,6 +37,7 @@ AC_CONFIG_AUX_DIR([build-aux])
+ 
+ AC_CONFIG_HEADERS([src/include/config.h:src/include/config.hin])
+ AC_CONFIG_SRCDIR([src/roff/groff/groff.cpp])
++AC_CONFIG_MACRO_DIR([m4])
+ 
+ AC_USE_SYSTEM_EXTENSIONS
+ 
+@@ -72,6 +73,7 @@ GROFF_DOC_CHECK
+ GROFF_MAKEINFO
+ GROFF_TEXI2DVI
+ AC_PROG_RANLIB
++AC_CHECK_TOOL([AR], [ar], [ar])
+ GROFF_INSTALL_SH
+ GROFF_INSTALL_INFO
+ AC_PROG_INSTALL
+-- 
+2.23.0
+
diff --git a/pkgs/tools/text/groff/default.nix b/pkgs/tools/text/groff/default.nix
new file mode 100644
index 00000000000..cb57fb2bb07
--- /dev/null
+++ b/pkgs/tools/text/groff/default.nix
@@ -0,0 +1,133 @@
+{ lib, stdenv, fetchurl, fetchpatch, perl
+, ghostscript #for postscript and html output
+, psutils, netpbm #for html output
+, buildPackages
+, autoreconfHook
+, pkg-config
+, texinfo
+}:
+
+stdenv.mkDerivation rec {
+  pname = "groff";
+  version = "1.22.4";
+
+  src = fetchurl {
+    url = "mirror://gnu/groff/${pname}-${version}.tar.gz";
+    sha256 = "14q2mldnr1vx0l9lqp9v2f6iww24gj28iyh4j2211hyynx67p3p7";
+  };
+
+  outputs = [ "out" "man" "doc" "info" "perl" ];
+
+  enableParallelBuilding = false;
+
+  patches = [
+    ./0001-Fix-cross-compilation-by-looking-for-ar.patch
+  ]
+  ++ lib.optionals (stdenv.cc.isClang && lib.versionAtLeast stdenv.cc.version "9") [
+    # https://trac.macports.org/ticket/59783
+    (fetchpatch {
+      url = "https://raw.githubusercontent.com/openembedded/openembedded-core/ce265cf467f1c3e5ba2edbfbef2170df1a727a52/meta/recipes-extended/groff/files/0001-Include-config.h.patch";
+      sha256 = "1b0mg31xkpxkzlx696nr08rcc7ndpaxdplvysy0hw5099c4n1wyf";
+    })
+  ];
+
+  postPatch = lib.optionalString (psutils != null) ''
+    substituteInPlace src/preproc/html/pre-html.cpp \
+      --replace "psselect" "${psutils}/bin/psselect"
+  '' + lib.optionalString (netpbm != null) ''
+    substituteInPlace src/preproc/html/pre-html.cpp \
+      --replace "pnmcut" "${lib.getBin netpbm}/bin/pnmcut" \
+      --replace "pnmcrop" "${lib.getBin netpbm}/bin/pnmcrop" \
+      --replace "pnmtopng" "${lib.getBin netpbm}/bin/pnmtopng"
+    substituteInPlace tmac/www.tmac \
+      --replace "pnmcrop" "${lib.getBin netpbm}/bin/pnmcrop" \
+      --replace "pngtopnm" "${lib.getBin netpbm}/bin/pngtopnm" \
+      --replace "@PNMTOPS_NOSETPAGE@" "${lib.getBin netpbm}/bin/pnmtops -nosetpage"
+  '';
+
+  buildInputs = [ ghostscript psutils netpbm perl ];
+  nativeBuildInputs = [ autoreconfHook pkg-config texinfo ];
+
+  # Builds running without a chroot environment may detect the presence
+  # of /usr/X11 in the host system, leading to an impure build of the
+  # package. To avoid this issue, X11 support is explicitly disabled.
+  # Note: If we ever want to *enable* X11 support, then we'll probably
+  # have to pass "--with-appresdir", too.
+  configureFlags = [
+    "--without-x"
+    "ac_cv_path_PERL=${buildPackages.perl}/bin/perl"
+  ] ++ lib.optionals (ghostscript != null) [
+    "--with-gs=${ghostscript}/bin/gs"
+  ] ++ lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform) [
+    "gl_cv_func_signbit=yes"
+  ];
+
+  makeFlags = lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform) [
+    # Trick to get the build system find the proper 'native' groff
+    # http://www.mail-archive.com/bug-groff@gnu.org/msg01335.html
+    "GROFF_BIN_PATH=${buildPackages.groff}/bin"
+    "GROFFBIN=${buildPackages.groff}/bin/groff"
+  ];
+
+  doCheck = true;
+
+  postInstall = ''
+    for f in 'man.local' 'mdoc.local'; do
+        cat '${./site.tmac}' >>"$out/share/groff/site-tmac/$f"
+    done
+
+    moveToOutput bin/gropdf $perl
+    moveToOutput bin/pdfmom $perl
+    moveToOutput bin/roff2text $perl
+    moveToOutput bin/roff2pdf $perl
+    moveToOutput bin/roff2ps $perl
+    moveToOutput bin/roff2dvi $perl
+    moveToOutput bin/roff2ps $perl
+    moveToOutput bin/roff2html $perl
+    moveToOutput bin/glilypond $perl
+    moveToOutput bin/mmroff $perl
+    moveToOutput bin/roff2x $perl
+    moveToOutput bin/afmtodit $perl
+    moveToOutput bin/gperl $perl
+    moveToOutput bin/chem $perl
+
+    moveToOutput bin/gpinyin $perl
+    moveToOutput lib/groff/gpinyin $perl
+    substituteInPlace $perl/bin/gpinyin \
+      --replace $out/lib/groff/gpinyin $perl/lib/groff/gpinyin
+
+    moveToOutput bin/groffer $perl
+    moveToOutput lib/groff/groffer $perl
+    substituteInPlace $perl/bin/groffer \
+      --replace $out/lib/groff/groffer $perl/lib/groff/groffer
+
+    moveToOutput bin/grog $perl
+    moveToOutput lib/groff/grog $perl
+    substituteInPlace $perl/bin/grog \
+      --replace $out/lib/groff/grog $perl/lib/groff/grog
+
+    find $perl/ -type f -print0 | xargs --null sed -i 's|${buildPackages.perl}|${perl}|'
+  '';
+
+  meta = with lib; {
+    homepage = "https://www.gnu.org/software/groff/";
+    description = "GNU Troff, a typesetting package that reads plain text and produces formatted output";
+    license = licenses.gpl3Plus;
+    platforms = platforms.all;
+    maintainers = with maintainers; [ pSub ];
+
+    longDescription = ''
+      groff is the GNU implementation of troff, a document formatting
+      system.  Included in this release are implementations of troff,
+      pic, eqn, tbl, grn, refer, -man, -mdoc, -mom, and -ms macros,
+      and drivers for PostScript, TeX dvi format, HP LaserJet 4
+      printers, Canon CAPSL printers, HTML and XHTML format (beta
+      status), and typewriter-like devices.  Also included is a
+      modified version of the Berkeley -me macros, the enhanced
+      version gxditview of the X11 xditview previewer, and an
+      implementation of the -mm macros.
+    '';
+
+    outputsToInstall = [ "out" "perl" ];
+  };
+}
diff --git a/pkgs/tools/text/groff/site.tmac b/pkgs/tools/text/groff/site.tmac
new file mode 100644
index 00000000000..776a7abb1da
--- /dev/null
+++ b/pkgs/tools/text/groff/site.tmac
@@ -0,0 +1,19 @@
+.
+.if n \{\
+.  \" Character translations for non-keyboard
+.  \" characters - to make them searchable
+.  if '\*[.T]'utf8' \{\
+.    char \- \N'45'
+.    char - \N'45'
+.    char ' \N'39'
+.    char \' \N'39'
+.  \}
+.
+.  \" Shut off SGR by default (groff colors)
+.  \" Require GROFF_SGR envvar defined to turn it on
+.  if '\V[GROFF_SGR]'' \
+.    output x X tty: sgr 0
+.\}
+.
+.ds doc-default-operating-system Nixpkgs
+.ds doc-volume-operating-system Nixpkgs
diff --git a/pkgs/tools/text/gtranslator/default.nix b/pkgs/tools/text/gtranslator/default.nix
new file mode 100644
index 00000000000..5bc99724e3f
--- /dev/null
+++ b/pkgs/tools/text/gtranslator/default.nix
@@ -0,0 +1,76 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, itstool
+, gettext
+, python3
+, wrapGAppsHook
+, libxml2
+, libgda
+, libhandy
+, libsoup
+, json-glib
+, gspell
+, glib
+, libdazzle
+, gtk3
+, gtksourceview4
+, gnome
+, gsettings-desktop-schemas
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gtranslator";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0d48nc11z0m91scy21ah56ysxns82zvswx8lglvlkig1vqvblgpc";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    itstool
+    gettext
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    libxml2
+    glib
+    gtk3
+    libdazzle
+    gtksourceview4
+    libgda
+    libhandy
+    libsoup
+    json-glib
+    gettext
+    gspell
+    gsettings-desktop-schemas
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson/meson_post_install.py
+    patchShebangs build-aux/meson/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+    };
+  };
+
+  meta = with lib; {
+    description = "GNOME translation making program";
+    homepage = "https://wiki.gnome.org/Apps/Gtranslator";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ jtojnar ];
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/gucci/default.nix b/pkgs/tools/text/gucci/default.nix
new file mode 100644
index 00000000000..c937e6c7ab1
--- /dev/null
+++ b/pkgs/tools/text/gucci/default.nix
@@ -0,0 +1,29 @@
+{ lib, buildGoPackage, fetchFromGitHub }:
+
+buildGoPackage rec {
+  pname = "gucci";
+  version = "0.1.0";
+
+  goPackagePath = "github.com/noqcks/gucci";
+
+  src = fetchFromGitHub {
+    owner = "noqcks";
+    repo = "gucci";
+    rev = version;
+    sha256 = "0ksrmzb3iggc7gm51fl0jbb15d0gmpclslpkq2sl2xjzk29pkllq";
+  };
+
+  goDeps = ./deps.nix;
+
+  ldflags = [
+    "-X main.AppVersion=${version}"
+  ];
+
+  meta = with lib; {
+    description = "A simple CLI templating tool written in golang";
+    homepage = "https://github.com/noqcks/gucci";
+    license = licenses.mit;
+    maintainers = [ maintainers.braydenjw ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/gucci/deps.nix b/pkgs/tools/text/gucci/deps.nix
new file mode 100644
index 00000000000..8e2cc5af3bf
--- /dev/null
+++ b/pkgs/tools/text/gucci/deps.nix
@@ -0,0 +1,30 @@
+[
+  {
+    goPackagePath = "gopkg.in/yaml.v2";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/yaml.v2";
+      rev = "5420a8b6744d3b0345ab293f6fcba19c978f1183";
+      sha256 = "0dwjrs2lp2gdlscs7bsrmyc5yf6mm4fvgw71bzr9mv2qrd2q73s1";
+    };
+  }
+  {
+    goPackagePath = "github.com/imdario/mergo";
+    fetch = {
+      type = "git";
+      url = "https://github.com/imdario/mergo";
+      rev = "v0.3.6";
+      sha256 = "1lbzy8p8wv439sqgf0n21q52flf2wbamp6qa1jkyv6an0nc952q7";
+    };
+  }
+  {
+    goPackagePath = "github.com/urfave/cli";
+    fetch = {
+      type = "git";
+      url = "https://github.com/urfave/cli";
+      rev = "v1.20.0";
+      sha256 = "0y6f4sbzkiiwrxbl15biivj8c7qwxnvm3zl2dd3mw4wzg4x10ygj";
+    };
+  }
+]
+
diff --git a/pkgs/tools/text/hck/default.nix b/pkgs/tools/text/hck/default.nix
new file mode 100644
index 00000000000..ebb66a07a8b
--- /dev/null
+++ b/pkgs/tools/text/hck/default.nix
@@ -0,0 +1,43 @@
+{ lib
+, rustPlatform
+, fetchFromGitHub
+, cmake
+, stdenv
+, CoreFoundation
+, Security
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "hck";
+  version = "0.7.1";
+
+  src = fetchFromGitHub {
+    owner = "sstadick";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-6PXhFOXWplj7yEyn7hOQSPS2YDGc1nxTs6wRseRvEVk=";
+  };
+
+  cargoSha256 = "sha256-VAtvc8K4282twB1MRY72+dCky3JmrTRjOPx1Ft7Oqt8=";
+
+  nativeBuildInputs = [ cmake ];
+
+  buildInputs = lib.optionals stdenv.isDarwin [ CoreFoundation Security ];
+
+  # link System as a dylib instead of a framework on macos
+  postPatch = lib.optionalString stdenv.isDarwin ''
+    core_affinity=../$(stripHash $cargoDeps)/core_affinity
+    oldHash=$(sha256sum $core_affinity/src/lib.rs | cut -d " " -f 1)
+    substituteInPlace $core_affinity/src/lib.rs --replace framework dylib
+    substituteInPlace $core_affinity/.cargo-checksum.json \
+      --replace $oldHash $(sha256sum $core_affinity/src/lib.rs | cut -d " " -f 1)
+  '';
+
+  meta = with lib; {
+    description = "A close to drop in replacement for cut that can use a regex delimiter instead of a fixed string";
+    homepage = "https://github.com/sstadick/hck";
+    changelog = "https://github.com/sstadick/hck/blob/v${version}/CHANGELOG.md";
+    license = with licenses; [ mit /* or */ unlicense ];
+    maintainers = with maintainers; [ figsoda ];
+  };
+}
diff --git a/pkgs/tools/text/highlight/default.nix b/pkgs/tools/text/highlight/default.nix
new file mode 100644
index 00000000000..57c607e69c6
--- /dev/null
+++ b/pkgs/tools/text/highlight/default.nix
@@ -0,0 +1,62 @@
+{ lib, stdenv, fetchFromGitLab, getopt, lua, boost, pkg-config, swig, perl, gcc }:
+
+let
+  self = stdenv.mkDerivation rec {
+    pname = "highlight";
+    version = "4.1";
+
+    src = fetchFromGitLab {
+      owner = "saalen";
+      repo = "highlight";
+      rev = "v${version}";
+      sha256 = "sha256-KktwbnL13Tcc2iWAjgqQSMSenUN6nYBEGbFrpB1kkr0=";
+    };
+
+    enableParallelBuilding = true;
+
+    nativeBuildInputs = [ pkg-config swig perl ]
+      ++ lib.optional stdenv.isDarwin gcc;
+
+    buildInputs = [ getopt lua boost ];
+
+    postPatch = ''
+      substituteInPlace src/makefile \
+        --replace "shell pkg-config" "shell $PKG_CONFIG"
+      substituteInPlace makefile \
+        --replace 'gzip' 'gzip -n'
+    '' + lib.optionalString stdenv.cc.isClang ''
+      substituteInPlace src/makefile \
+          --replace 'CXX=g++' 'CXX=clang++'
+    '';
+
+    preConfigure = ''
+      makeFlags="PREFIX=$out conf_dir=$out/etc/highlight/ CXX=$CXX AR=$AR"
+    '';
+
+    # This has to happen _before_ the main build because it does a
+    # `make clean' for some reason.
+    preBuild = lib.optionalString (!stdenv.isDarwin) ''
+      make -C extras/swig $makeFlags perl
+    '';
+
+    postCheck = lib.optionalString (!stdenv.isDarwin) ''
+      perl -Iextras/swig extras/swig/testmod.pl
+    '';
+
+    preInstall = lib.optionalString (!stdenv.isDarwin) ''
+      mkdir -p $out/${perl.libPrefix}
+      install -m644 extras/swig/highlight.{so,pm} $out/${perl.libPrefix}
+      make -C extras/swig clean # Clean up intermediate files.
+    '';
+
+    meta = with lib; {
+      description = "Source code highlighting tool";
+      homepage = "http://www.andre-simon.de/doku/highlight/en/highlight.php";
+      platforms = platforms.unix;
+      maintainers = with maintainers; [ willibutz ];
+    };
+  };
+
+in
+  if stdenv.isDarwin then self
+  else perl.pkgs.toPerlModule self
diff --git a/pkgs/tools/text/hottext/default.nix b/pkgs/tools/text/hottext/default.nix
new file mode 100644
index 00000000000..f6c70013b4c
--- /dev/null
+++ b/pkgs/tools/text/hottext/default.nix
@@ -0,0 +1,40 @@
+{ lib, nimPackages, fetchurl, gentium, makeDesktopItem }:
+
+nimPackages.buildNimPackage rec {
+  pname = "hottext";
+  version = "1.4";
+
+  nimBinOnly = true;
+
+  src = fetchurl {
+    url = "https://git.sr.ht/~ehmry/hottext/archive/v${version}.tar.gz";
+    sha256 = "sha256-hIUofi81zowSMbt1lUsxCnVzfJGN3FEiTtN8CEFpwzY=";
+  };
+
+  buildInputs = with nimPackages; [
+    pixie
+    sdl2
+  ];
+
+  HOTTEXT_FONT_PATH = "${gentium}/share/fonts/truetype/GentiumPlus-Regular.ttf";
+
+  desktopItem = makeDesktopItem {
+    categories = [ "Utility" ];
+    comment = meta.description;
+    desktopName = pname;
+    exec = pname;
+    name = pname;
+  };
+
+  postInstall = ''
+    cp -r $desktopItem/* $out
+  '';
+
+  meta = with lib; {
+    broken = true; # Needs to be updated to latest Pixie API.
+    description = "Simple RSVP speed-reading utility";
+    license = licenses.unlicense;
+    homepage = "https://git.sr.ht/~ehmry/hottext";
+    maintainers = with maintainers; [ ehmry ];
+  };
+}
diff --git a/pkgs/tools/text/html-tidy/default.nix b/pkgs/tools/text/html-tidy/default.nix
new file mode 100644
index 00000000000..d4bb26a0a77
--- /dev/null
+++ b/pkgs/tools/text/html-tidy/default.nix
@@ -0,0 +1,32 @@
+{ lib, stdenv, fetchFromGitHub, cmake, libxslt }:
+
+stdenv.mkDerivation rec {
+  pname = "html-tidy";
+  version = "5.8.0";
+
+  src = fetchFromGitHub {
+    owner = "htacg";
+    repo = "tidy-html5";
+    rev = version;
+    sha256 = "sha256-ZMz0NySxzX2XHiqB8f5asvwjIG6kdIcq8Gb3EbAxBaU=";
+  };
+
+  nativeBuildInputs = [ cmake libxslt/*manpage*/ ];
+
+  cmakeFlags = [];
+
+  # ATM bin/tidy is statically linked, as upstream provides no other option yet.
+  # https://github.com/htacg/tidy-html5/issues/326#issuecomment-160322107
+
+  meta = with lib; {
+    description = "A HTML validator and `tidier'";
+    longDescription = ''
+      HTML Tidy is a command-line tool and C library that can be
+      used to validate and fix HTML data.
+    '';
+    license = licenses.libpng; # very close to it - the 3 clauses are identical
+    homepage = "http://html-tidy.org";
+    platforms = platforms.all;
+    maintainers = with maintainers; [ edwtjo ];
+  };
+}
diff --git a/pkgs/tools/text/html2text/default.nix b/pkgs/tools/text/html2text/default.nix
new file mode 100644
index 00000000000..fff3e44baf6
--- /dev/null
+++ b/pkgs/tools/text/html2text/default.nix
@@ -0,0 +1,33 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "html2text";
+  version = "1.3.2a";
+
+  src = fetchurl {
+    url = "http://www.mbayer.de/html2text/downloads/html2text-${version}.tar.gz";
+    sha256 = "000b39d5d910b867ff7e087177b470a1e26e2819920dcffd5991c33f6d480392";
+  };
+
+  preConfigure = ''
+    substituteInPlace configure \
+        --replace /bin/echo echo \
+        --replace CXX=unknown ':'
+  '';
+
+  # the --prefix has no effect
+  installPhase = ''
+    mkdir -p $out/bin $out/man/man{1,5}
+    cp html2text $out/bin
+    cp html2text.1.gz $out/man/man1
+    cp html2textrc.5.gz $out/man/man5
+  '';
+
+  meta = {
+    description = "Convert HTML to plain text";
+    homepage = "http://www.mbayer.de/html2text/";
+    license = lib.licenses.gpl2Plus;
+    platforms = lib.platforms.unix;
+    maintainers = [ lib.maintainers.eikek ];
+  };
+}
diff --git a/pkgs/tools/text/hyx/default.nix b/pkgs/tools/text/hyx/default.nix
new file mode 100644
index 00000000000..28b4765ede4
--- /dev/null
+++ b/pkgs/tools/text/hyx/default.nix
@@ -0,0 +1,30 @@
+{ lib, stdenv, fetchurl, memstreamHook }:
+
+stdenv.mkDerivation rec {
+  pname = "hyx";
+  version = "2021.06.09";
+
+  src = fetchurl {
+    url = "https://yx7.cc/code/hyx/hyx-${lib.replaceStrings [ "-" ] [ "." ] version}.tar.xz";
+    sha256 = "sha256-jU8U5YWE1syPBOQ8o4BC7tIYiCo4kknCCwhnMCVtpes=";
+  };
+
+  postPatch = lib.optionalString stdenv.isDarwin ''
+    substituteInPlace Makefile \
+      --replace "-Wl,-z,relro,-z,now -fpic -pie" ""
+  '';
+
+  buildInputs = lib.optional (stdenv.system == "x86_64-darwin") memstreamHook;
+
+  installPhase = ''
+    install -vD hyx $out/bin/hyx
+  '';
+
+  meta = with lib; {
+    description = "minimalistic but powerful Linux console hex editor";
+    homepage = "https://yx7.cc/code/";
+    license = licenses.mit;
+    maintainers = with maintainers; [ fpletz ];
+    platforms = with platforms; linux ++ darwin;
+  };
+}
diff --git a/pkgs/tools/text/icdiff/default.nix b/pkgs/tools/text/icdiff/default.nix
new file mode 100644
index 00000000000..715a4dbaae2
--- /dev/null
+++ b/pkgs/tools/text/icdiff/default.nix
@@ -0,0 +1,34 @@
+{ lib, fetchFromGitHub, python3Packages, bash, git, less }:
+
+python3Packages.buildPythonApplication rec {
+  pname = "icdiff";
+  version = "1.9.5";
+
+  src = fetchFromGitHub {
+    owner = "jeffkaufman";
+    repo = "icdiff";
+    rev = "release-${version}";
+    sha256 = "080v8h09pv8qwplin4kwfm0kmqjwdqjfxbpcdrv16sv4hwfwl5qd";
+  };
+
+  checkInputs = [
+    bash
+    git
+    less
+  ];
+
+  # error: could not lock config file /homeless-shelter/.gitconfig: No such file or directory
+  doCheck = false;
+
+  checkPhase = ''
+    patchShebangs test.sh
+    ./test.sh ${python3Packages.python.interpreter}
+  '';
+
+  meta = with lib; {
+    homepage = "https://www.jefftk.com/icdiff";
+    description = "Side-by-side highlighted command line diffs";
+    maintainers = with maintainers; [ ];
+    license = licenses.psfl;
+  };
+}
diff --git a/pkgs/tools/text/igrep/default.nix b/pkgs/tools/text/igrep/default.nix
new file mode 100644
index 00000000000..b7fc915c44d
--- /dev/null
+++ b/pkgs/tools/text/igrep/default.nix
@@ -0,0 +1,36 @@
+{ lib
+, rustPlatform
+, fetchFromGitHub
+, stdenv
+, Security
+, testVersion
+, igrep
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "igrep";
+  version = "0.2.0";
+
+  src = fetchFromGitHub {
+    owner = "konradsz";
+    repo = "igrep";
+    rev = "v${version}";
+    sha256 = "sha256-CH0wf9EhNnfi93W/4IJf6bPqU4pgw6Q9965Wjln9pso=";
+  };
+
+  cargoSha256 = "sha256-VnZuRLBt/Q+D89+jKm0rak+ID5oNbvN1k8or3pYzfIM=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ Security ];
+
+  passthru.tests = {
+    version = testVersion { package = igrep; command = "ig --version"; };
+  };
+
+  meta = with lib; {
+    description = "Interactive Grep";
+    homepage = "https://github.com/konradsz/igrep";
+    changelog = "https://github.com/konradsz/igrep/blob/v${version}/CHANGELOG.md";
+    license = licenses.mit;
+    maintainers = with maintainers; [ _0x4A6F ];
+  };
+}
diff --git a/pkgs/tools/text/invoice2data/default.nix b/pkgs/tools/text/invoice2data/default.nix
new file mode 100644
index 00000000000..941f2d6f493
--- /dev/null
+++ b/pkgs/tools/text/invoice2data/default.nix
@@ -0,0 +1,58 @@
+{ lib
+, fetchFromGitHub
+, imagemagick
+, python3
+, tesseract
+, xpdf
+}:
+
+python3.pkgs.buildPythonApplication rec {
+  pname = "invoice2data";
+  version = "0.3.6";
+  format = "setuptools";
+
+  src = fetchFromGitHub {
+    owner = "invoice-x";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-t1jgLyKtQsLINlnkCdSbVfTM6B/EiD1yGtx9UHjyZVE=";
+  };
+
+  nativeBuildInputs = with python3.pkgs; [
+    setuptools-git
+  ];
+
+  propagatedBuildInputs = with python3.pkgs; [
+    chardet
+    dateparser
+    pdfminer
+    pillow
+    pyyaml
+    unidecode
+  ];
+
+  postPatch = ''
+    substituteInPlace setup.cfg \
+      --replace "pytest-runner" ""
+  '';
+
+  makeWrapperArgs = ["--prefix" "PATH" ":" (lib.makeBinPath [
+    imagemagick
+    tesseract
+    xpdf
+  ])];
+
+  # Tests fails even when ran manually on my ubuntu machine !!
+  doCheck = false;
+
+  pythonImportsCheck = [
+    "invoice2data"
+  ];
+
+  meta = with lib; {
+    description = "Data extractor for PDF invoices";
+    homepage = "https://github.com/invoice-x/invoice2data";
+    license = licenses.mit;
+    maintainers = with maintainers; [ psyanticy ];
+  };
+}
diff --git a/pkgs/tools/text/ispell/default.nix b/pkgs/tools/text/ispell/default.nix
new file mode 100644
index 00000000000..9a3f37cc64a
--- /dev/null
+++ b/pkgs/tools/text/ispell/default.nix
@@ -0,0 +1,38 @@
+{ lib, stdenv, fetchurl, bison, ncurses }:
+
+stdenv.mkDerivation rec {
+  pname = "ispell";
+  version = "3.4.04";
+
+  src = fetchurl {
+    url = "https://www.cs.hmc.edu/~geoff/tars/${pname}-${version}.tar.gz";
+    sha256 = "sha256-h7zW8FIdhaCjp4NCFZVtdOvEkxRMx8eR+HvmhyzP4T4=";
+  };
+
+  buildInputs = [ bison ncurses ];
+
+  postPatch = ''
+    cat >> local.h <<EOF
+    ${lib.optionalString (!stdenv.isDarwin) "#define USG"}
+    #define TERMLIB "-lncurses"
+    #define LANGUAGES "{american,MASTERDICTS=american.med,HASHFILES=americanmed.hash}"
+    #define MASTERHASH "americanmed.hash"
+    #define BINDIR "$out/bin"
+    #define LIBDIR "$out/lib"
+    #define ELISPDIR "{$out}/share/emacs/site-lisp"
+    #define TEXINFODIR "$out/share/info"
+    #define MAN1DIR "$out/share/man/man1"
+    #define MAN4DIR "$out/share/man/man4"
+    #define MAN45DIR "$out/share/man/man5"
+    #define MINIMENU
+    #define HAS_RENAME
+    EOF
+  '';
+
+  meta = with lib; {
+    description = "An interactive spell-checking program for Unix";
+    homepage = "https://www.cs.hmc.edu/~geoff/ispell.html";
+    license = licenses.free;
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/jbofihe/default.nix b/pkgs/tools/text/jbofihe/default.nix
new file mode 100644
index 00000000000..111b019c3b1
--- /dev/null
+++ b/pkgs/tools/text/jbofihe/default.nix
@@ -0,0 +1,29 @@
+{ lib, stdenv, fetchFromGitHub, bison, flex, perl, }:
+
+stdenv.mkDerivation rec {
+  pname = "jbofihe";
+  version = "0.43";
+
+  src = fetchFromGitHub {
+    owner = "lojban";
+    repo = "jbofihe";
+    rev = "v${version}";
+    sha256 = "1xx7x1256sjncyzx656jl6jl546vn8zz0siymqalz6v9yf341p98";
+  };
+
+  nativeBuildInputs = [ bison flex perl ];
+
+  doCheck = true;
+  checkPhase = ''
+    runHook preCheck
+    (cd tests && ./run *.in)
+    runHook postCheck
+  '';
+
+  meta = with lib; {
+    description = "Parser & analyser for Lojban";
+    homepage = "https://github.com/lojban/jbofihe";
+    license = licenses.gpl2Only;
+    maintainers = with maintainers; [ chkno ];
+  };
+}
diff --git a/pkgs/tools/text/jsawk/default.nix b/pkgs/tools/text/jsawk/default.nix
new file mode 100644
index 00000000000..4efaf56ccf6
--- /dev/null
+++ b/pkgs/tools/text/jsawk/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchFromGitHub, makeWrapper, spidermonkey_78 }:
+
+stdenv.mkDerivation {
+  pname = "jsawk";
+  version = "1.5-pre";
+  src = fetchFromGitHub {
+    owner = "micha";
+    repo = "jsawk";
+    rev = "5a14c4af3c7b59807701b70a954ecefc6f77e978";
+    sha256 = "0z3vdr3c8nvdrrxkjv9b4xg47mdb2hsknxpimw6shgwbigihapyr";
+  };
+  dontBuild = true;
+  nativeBuildInputs = [ makeWrapper ];
+  installPhase = ''
+    mkdir -p $out/bin
+    cp $src/jsawk $out/bin/
+    wrapProgram $out/bin/jsawk \
+      --prefix PATH : "${spidermonkey_78}/bin"
+  '';
+
+  meta = {
+    description = "Like awk, but for JSON";
+    homepage = "https://github.com/micha/jsawk";
+    license = lib.licenses.publicDomain;
+    maintainers = with lib.maintainers; [ puffnfresh ];
+    platforms = lib.platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/jumanpp/default.nix b/pkgs/tools/text/jumanpp/default.nix
new file mode 100644
index 00000000000..5fb5ec88d67
--- /dev/null
+++ b/pkgs/tools/text/jumanpp/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchurl, cmake, protobuf, libiconv }:
+
+stdenv.mkDerivation rec {
+  pname = "jumanpp";
+  version = "2.0.0-rc3";
+
+  src = fetchurl {
+    url = "https://github.com/ku-nlp/${pname}/releases/download/v${version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-ASdr6qbkSe71M7QmuuwidCa4xQhDVoXBJ2XqvSY53pQ=";
+  };
+
+  nativeBuildInputs = [ cmake ];
+  buildInputs = [ protobuf ]
+    ++ lib.optional stdenv.isDarwin libiconv;
+
+  meta = with lib; {
+    description = "A Japanese morphological analyser using a recurrent neural network language model (RNNLM)";
+    longDescription = ''
+      JUMAN++ is a new morphological analyser that considers semantic
+      plausibility of word sequences by using a recurrent neural network
+      language model (RNNLM).
+    '';
+    homepage = "https://nlp.ist.i.kyoto-u.ac.jp/index.php?JUMAN++";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ mt-caret ];
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/kakasi/default.nix b/pkgs/tools/text/kakasi/default.nix
new file mode 100644
index 00000000000..fa509f1b4a7
--- /dev/null
+++ b/pkgs/tools/text/kakasi/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, fetchurl, libiconv }:
+
+stdenv.mkDerivation rec {
+  pname = "kakasi";
+  version = "2.3.6";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ libiconv ];
+
+  meta = with lib; {
+    description = "Kanji Kana Simple Inverter";
+    longDescription = ''
+      KAKASI is the language processing filter to convert Kanji
+      characters to Hiragana, Katakana or Romaji and may be
+      helpful to read Japanese documents.
+    '';
+    homepage    = "http://kakasi.namazu.org/";
+    license     = licenses.gpl2Plus;
+    platforms   = platforms.unix;
+  };
+
+  src = fetchurl {
+    url = "http://kakasi.namazu.org/stable/kakasi-${version}.tar.xz";
+    sha256 = "1qry3xqb83pjgxp3my8b1sy77z4f0893h73ldrvdaky70cdppr9f";
+  };
+
+  postPatch = ''
+    for a in tests/kakasi-* ; do
+      substituteInPlace $a \
+        --replace "/bin/echo" echo
+    done
+  '';
+
+  doCheck = false; # fails 1 of 6 tests
+
+}
diff --git a/pkgs/tools/text/kdiff3/default.nix b/pkgs/tools/text/kdiff3/default.nix
new file mode 100644
index 00000000000..07f82c08591
--- /dev/null
+++ b/pkgs/tools/text/kdiff3/default.nix
@@ -0,0 +1,39 @@
+{ mkDerivation
+, lib
+, fetchurl
+, extra-cmake-modules
+, kdoctools
+, wrapGAppsHook
+, boost
+, kcrash
+, kconfig
+, kinit
+, kparts
+, kiconthemes
+}:
+
+mkDerivation rec {
+  pname = "kdiff3";
+  version = "1.9.5";
+
+  src = fetchurl {
+    url = "https://download.kde.org/stable/${pname}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-CDchWW2dQ3O8LxKYOUqN21tVp61NckKTOnzYrmRoPBo=";
+  };
+
+  buildInputs = [ boost ];
+
+  nativeBuildInputs = [ extra-cmake-modules kdoctools wrapGAppsHook ];
+
+  propagatedBuildInputs = [ kconfig kcrash kinit kparts kiconthemes ];
+
+  cmakeFlags = [ "-Wno-dev" ];
+
+  meta = with lib; {
+    description = "Compares and merges 2 or 3 files or directories";
+    homepage = "https://invent.kde.org/sdk/kdiff3";
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [ peterhoeg ];
+    platforms = with platforms; linux;
+  };
+}
diff --git a/pkgs/tools/text/kytea/default.nix b/pkgs/tools/text/kytea/default.nix
new file mode 100644
index 00000000000..9cbc2c030a4
--- /dev/null
+++ b/pkgs/tools/text/kytea/default.nix
@@ -0,0 +1,32 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+
+  pname = "kytea";
+  version = "0.4.7";
+
+  src = fetchurl {
+    url    = "http://www.phontron.com/kytea/download/${pname}-${version}.tar.gz";
+    sha256 = "0ilzzwn5vpvm65bnbyb9f5rxyxy3jmbafw9w0lgl5iad1ka36jjk";
+  };
+
+  patches = [ ./gcc-O3.patch ];
+
+  NIX_CFLAGS_COMPILE = lib.optionalString stdenv.cc.isClang "-Wno-error=c++11-narrowing";
+
+  meta = with lib; {
+    homepage = "http://www.phontron.com/kytea/";
+    description = "General toolkit developed for analyzing text";
+
+    longDescription = ''
+      A general toolkit developed for analyzing text, with a focus on Japanese,
+      Chinese and other languages requiring word or morpheme segmentation.
+    '';
+
+    license = licenses.asl20;
+
+    maintainers = with maintainers; [ ericsagnes ];
+    platforms = platforms.unix;
+  };
+
+}
diff --git a/pkgs/tools/text/kytea/gcc-O3.patch b/pkgs/tools/text/kytea/gcc-O3.patch
new file mode 100644
index 00000000000..71b1d0c3b16
--- /dev/null
+++ b/pkgs/tools/text/kytea/gcc-O3.patch
@@ -0,0 +1,13 @@
+diff --git a/src/lib/kytea-util.cpp b/src/lib/kytea-util.cpp
+index 7c8c4c6..4492df1 100644
+--- a/src/lib/kytea-util.cpp
++++ b/src/lib/kytea-util.cpp
+@@ -49,5 +49,8 @@ void checkValueVecEqual(const std::vector<T> * a, const std::vector<T> * b) {
+ 
++template void checkValueVecEqual(const std::vector<unsigned int> & a, const std::vector<unsigned int> & b);
+ template void checkValueVecEqual(const std::vector<unsigned int> * a, const std::vector<unsigned int> * b);
++template void checkValueVecEqual(const std::vector<short> & a, const std::vector<short> & b);
+ template void checkValueVecEqual(const std::vector<short> * a, const std::vector<short> * b);
+ template void checkValueVecEqual(const std::vector<vector<KyteaString> > * a, const std::vector<vector<KyteaString> > * b);
++template void checkValueVecEqual(const std::vector<int> & a, const std::vector<int> & b);
+ template void checkValueVecEqual(const std::vector<int> * a, const std::vector<int> * b);
diff --git a/pkgs/tools/text/l2md/default.nix b/pkgs/tools/text/l2md/default.nix
new file mode 100644
index 00000000000..758130e9f0a
--- /dev/null
+++ b/pkgs/tools/text/l2md/default.nix
@@ -0,0 +1,32 @@
+{ lib, stdenv, fetchgit, libgit2 }:
+
+stdenv.mkDerivation rec {
+  pname = "l2md";
+  version = "unstable-2021-10-27";
+
+  src = fetchgit {
+    url = "https://git.kernel.org/pub/scm/linux/kernel/git/dborkman/l2md.git";
+    rev = "9db252bc1716ebaf0abd3a47a59ea78e4e6253d6";
+    sha256 = "sha256-H/leDUwQM55akyXsmTnI2YsnG4i1KQtf4bBt1fizy8E=";
+  };
+
+  buildInputs = [ libgit2 ];
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp l2md $out/bin
+  '';
+
+  meta = with lib; {
+    description = "Convert public-inbox archives to maildir messages";
+    longDescription = ''
+      Quick and dirty hack to import lore.kernel.org list archives via git,
+      to export them in maildir format or through a pipe, and to keep them
+      periodically synced.
+    '';
+    homepage = "https://git.kernel.org/pub/scm/linux/kernel/git/dborkman/l2md.git";
+    license = licenses.gpl2Only;
+    maintainers = with maintainers; [ yoctocell ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/languagetool/default.nix b/pkgs/tools/text/languagetool/default.nix
new file mode 100644
index 00000000000..96dc84e94db
--- /dev/null
+++ b/pkgs/tools/text/languagetool/default.nix
@@ -0,0 +1,38 @@
+{ lib, stdenv, fetchzip, jre, makeWrapper }:
+
+stdenv.mkDerivation rec {
+  pname = "LanguageTool";
+  version = "5.6";
+
+  src = fetchzip {
+    url = "https://www.languagetool.org/download/${pname}-${version}.zip";
+    sha256 = "sha256-HsRAu8exGXCGF0P7wZaDtuAKRDmNjMF9P2hFliZ1RXo=";
+  };
+  nativeBuildInputs = [ makeWrapper ];
+  buildInputs = [ jre ];
+
+  installPhase = ''
+    runHook preInstall
+
+    mkdir -p $out/share
+    mv -- * $out/share/
+
+    for lt in languagetool{,-commandline,-server};do
+      makeWrapper ${jre}/bin/java $out/bin/$lt \
+        --add-flags "-cp $out/share/ -jar $out/share/$lt.jar"
+    done
+
+    makeWrapper ${jre}/bin/java $out/bin/languagetool-http-server \
+      --add-flags "-cp $out/share/languagetool-server.jar org.languagetool.server.HTTPServer"
+
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    homepage = "https://languagetool.org";
+    license = licenses.lgpl21Plus;
+    maintainers = with maintainers; [ edwtjo ];
+    platforms = jre.meta.platforms;
+    description = "A proofreading program for English, French German, Polish, and more";
+  };
+}
diff --git a/pkgs/tools/text/ledger2beancount/default.nix b/pkgs/tools/text/ledger2beancount/default.nix
new file mode 100644
index 00000000000..caa6335d452
--- /dev/null
+++ b/pkgs/tools/text/ledger2beancount/default.nix
@@ -0,0 +1,59 @@
+{ lib, stdenv, fetchFromGitHub, makeWrapper, perlPackages, beancount }:
+
+with lib;
+
+let
+  perlDeps = with perlPackages; [
+    DateCalc
+    DateTimeFormatStrptime
+    enum
+    FileBaseDir
+    GetoptLongDescriptive
+    ListMoreUtils
+    RegexpCommon
+    StringInterpolate
+    YAMLLibYAML
+  ];
+
+in stdenv.mkDerivation rec {
+  pname = "ledger2beancount";
+  version = "2.6";
+
+  src = fetchFromGitHub {
+    owner = "beancount";
+    repo = "ledger2beancount";
+    rev = version;
+    sha256 = "sha256-0Br+zuSUYrNP+ZL/FtNoaYoYBYho5kVfxu0tqKJSuBk=";
+  };
+
+  dontBuild = true;
+
+  nativeBuildInputs = [ makeWrapper ];
+  buildInputs = [ perlPackages.perl beancount ] ++ perlDeps;
+
+  makeFlags = [ "prefix=$(out)" ];
+  installFlags = [ "INSTALL=install" ];
+
+  installPhase = ''
+    mkdir -p $out
+    cp -r $src/bin $out/bin
+  '';
+
+  postFixup = ''
+    wrapProgram "$out/bin/ledger2beancount" \
+      --set PERL5LIB "${perlPackages.makeFullPerlPath perlDeps}"
+  '';
+
+  meta = {
+    description = "Ledger to Beancount text-based converter";
+    longDescription = ''
+      A script to automatically convert Ledger-based textual ledgers to Beancount ones.
+
+      Conversion is based on (concrete) syntax, so that information that is not meaningful for accounting reasons but still valuable (e.g., comments, formatting, etc.) can be preserved.
+    '';
+    homepage = "https://github.com/beancount/ledger2beancount";
+    license = licenses.gpl3Plus;
+    platforms = platforms.all;
+    maintainers = with maintainers; [ pablovsky ];
+  };
+}
diff --git a/pkgs/tools/text/link-grammar/default.nix b/pkgs/tools/text/link-grammar/default.nix
new file mode 100644
index 00000000000..c685ef60331
--- /dev/null
+++ b/pkgs/tools/text/link-grammar/default.nix
@@ -0,0 +1,65 @@
+{ lib
+, stdenv
+, fetchurl
+, pkg-config
+, python3
+, sqlite
+, libedit
+, runCommand
+, dieHook
+}:
+
+let
+
+link-grammar = stdenv.mkDerivation rec {
+  pname = "link-grammar";
+  version = "5.10.2";
+
+  outputs = [ "bin" "out" "dev" "man" ];
+
+  src = fetchurl {
+    url = "http://www.abisource.com/downloads/${pname}/${version}/${pname}-${version}.tar.gz";
+    sha256 = "sha256-KM7HUuqg44l66WEzO2knRZ+Laf7+aMKqUnKYPX24abY=";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    python3
+  ];
+
+  buildInputs = [
+    sqlite
+    libedit
+  ];
+
+  configureFlags = [
+    "--disable-java-bindings"
+  ];
+
+  doCheck = true;
+
+  passthru.tests = {
+    quick = runCommand "link-grammar-quick-test" {
+      buildInputs = [
+        link-grammar
+        dieHook
+      ];
+    } ''
+      echo "Furiously sleep ideas green colorless." | link-parser en | grep "No complete linkages found." || die "Grammaticaly invalid sentence was parsed."
+      echo "Colorless green ideas sleep furiously." | link-parser en | grep "Found .* linkages." || die "Grammaticaly valid sentence was not parsed."
+      touch $out
+    '';
+  };
+
+  meta = with lib; {
+    description = "A Grammar Checking library";
+    homepage = "https://www.abisource.com/projects/link-grammar/";
+    changelog = "https://github.com/opencog/link-grammar/blob/link-grammar-${version}/ChangeLog";
+    license = licenses.lgpl21Only;
+    maintainers = with maintainers; [ jtojnar ];
+    platforms = platforms.unix;
+  };
+};
+
+in
+  link-grammar
diff --git a/pkgs/tools/text/lv/default.nix b/pkgs/tools/text/lv/default.nix
new file mode 100644
index 00000000000..48ed867c8e4
--- /dev/null
+++ b/pkgs/tools/text/lv/default.nix
@@ -0,0 +1,33 @@
+{ lib, stdenv, fetchurl, ncurses }:
+
+stdenv.mkDerivation rec {
+  pname = "lv";
+  version = "4.51";
+
+  src = fetchurl {
+    url = "mirror://debian/pool/main/l/${pname}/${pname}_${version}.orig.tar.gz";
+    sha256 = "0yf3idz1qspyff1if41xjpqqcaqa8q8icslqlnz0p9dj36gmm5l3";
+  };
+
+  makeFlags = [ "prefix=${placeholder "out"}" ];
+
+  buildInputs = [ ncurses ];
+
+  configurePhase = ''
+    mkdir -p build
+    cd build
+    ../src/configure
+  '';
+
+  preInstall = ''
+    mkdir -p $out/bin
+  '';
+
+  meta = with lib; {
+    description = "Powerful multi-lingual file viewer / grep";
+    homepage = "https://web.archive.org/web/20160310122517/www.ff.iij4u.or.jp/~nrt/lv/";
+    license = licenses.gpl2;
+    platforms = with platforms; linux ++ darwin;
+    maintainers = with maintainers; [ kayhide ];
+  };
+}
diff --git a/pkgs/tools/text/m2r/default.nix b/pkgs/tools/text/m2r/default.nix
new file mode 100644
index 00000000000..f6dda712d0b
--- /dev/null
+++ b/pkgs/tools/text/m2r/default.nix
@@ -0,0 +1,32 @@
+{ lib
+, buildPythonApplication
+, fetchFromGitHub
+, docutils
+, mistune
+, pygments
+}:
+
+buildPythonApplication rec {
+  pname = "m2r";
+  version = "0.2.1";
+
+  src = fetchFromGitHub {
+    owner = "miyakogi";
+    repo = pname;
+    rev = "v${version}";
+    hash = "sha256-JNLPEXMoiISh4RnKP+Afj9/PJp9Lrx9UYHsfuGAL7uI=";
+  };
+
+  buildInputs = [
+    docutils
+    mistune
+    pygments
+  ];
+
+  meta = with lib; {
+    homepage = "https://github.com/miyakogi/m2r";
+    description = "Markdown-to-RestructuredText converter";
+    license = licenses.mit;
+    maintainers = with maintainers; [ AndersonTorres ];
+  };
+}
diff --git a/pkgs/tools/text/mairix/default.nix b/pkgs/tools/text/mairix/default.nix
new file mode 100644
index 00000000000..aa58ecdd35a
--- /dev/null
+++ b/pkgs/tools/text/mairix/default.nix
@@ -0,0 +1,26 @@
+{ lib, stdenv, fetchurl, zlib, bzip2, bison, flex }:
+
+stdenv.mkDerivation rec {
+  pname = "mairix";
+  version = "0.24";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/mairix/mairix-${version}.tar.gz";
+    sha256 = "0msaxz5c5hf7k1ci16i67m4ynrbrpsxbqzk84nz6z2vnkh3jww50";
+  };
+
+  buildInputs = [ zlib bzip2 bison flex ];
+
+  # https://github.com/rc0/mairix/pull/19
+  patches = [ ./mmap.patch ];
+
+  enableParallelBuilding = true;
+
+  meta = {
+    homepage = "http://www.rc0.org.uk/mairix";
+    license = lib.licenses.gpl2Plus;
+    description = "Program for indexing and searching email messages stored in maildir, MH or mbox";
+    maintainers = with lib.maintainers; [viric];
+    platforms = with lib.platforms; all;
+  };
+}
diff --git a/pkgs/tools/text/mairix/mmap.patch b/pkgs/tools/text/mairix/mmap.patch
new file mode 100644
index 00000000000..241083f2dde
--- /dev/null
+++ b/pkgs/tools/text/mairix/mmap.patch
@@ -0,0 +1,161 @@
+Making mairix work with mbox files over 2GB.
+
+https://github.com/rc0/mairix/pull/19
+
+diff --git a/mairix.h b/mairix.h
+index 2480492..cb25824 100644
+--- a/mairix.h
++++ b/mairix.h
+@@ -327,9 +327,9 @@ enum data_to_rfc822_error {
+   DTR8_BAD_HEADERS, /* corrupt headers */
+   DTR8_BAD_ATTACHMENT /* corrupt attachment (e.g. no body part) */
+ };
+-struct rfc822 *data_to_rfc822(struct msg_src *src, char *data, int length, enum data_to_rfc822_error *error);
+-void create_ro_mapping(const char *filename, unsigned char **data, int *len);
+-void free_ro_mapping(unsigned char *data, int len);
++struct rfc822 *data_to_rfc822(struct msg_src *src, char *data, size_t length, enum data_to_rfc822_error *error);
++void create_ro_mapping(const char *filename, unsigned char **data, size_t *len);
++void free_ro_mapping(unsigned char *data, size_t len);
+ char *format_msg_src(struct msg_src *src);
+ 
+ /* In tok.c */
+diff --git a/mbox.c b/mbox.c
+index ebbfa78..396e27d 100644
+--- a/mbox.c
++++ b/mbox.c
+@@ -816,7 +816,7 @@ void build_mbox_lists(struct database *db, const char *folder_base, /*{{{*/
+         mb->n_old_msgs_valid = mb->n_msgs;
+       } else {
+         unsigned char *va;
+-        int len;
++        size_t len;
+         create_ro_mapping(mb->path, &va, &len);
+         if (va) {
+           rescan_mbox(mb, (char *) va, len);
+@@ -852,7 +852,7 @@ int add_mbox_messages(struct database *db)/*{{{*/
+   int any_new = 0;
+   int N;
+   unsigned char *va;
+-  int valen;
++  size_t valen;
+   enum data_to_rfc822_error error;
+ 
+   for (i=0; i<db->n_mboxen; i++) {
+diff --git a/reader.c b/reader.c
+index 71ac5bd..18f0108 100644
+--- a/reader.c
++++ b/reader.c
+@@ -81,7 +81,8 @@ static void read_toktable2_db(char *data, struct toktable2_db *toktable, int sta
+ /*}}}*/
+ struct read_db *open_db(char *filename)/*{{{*/
+ {
+-  int fd, len;
++  int fd;
++  size_t len;
+   char *data;
+   struct stat sb;
+   struct read_db *result;
+diff --git a/reader.h b/reader.h
+index 9b5dfa3..d709cc4 100644
+--- a/reader.h
++++ b/reader.h
+@@ -138,7 +138,7 @@ struct toktable2_db {/*{{{*/
+ struct read_db {/*{{{*/
+   /* Raw file parameters, needed later for munmap */
+   char *data;
+-  int len;
++  size_t len;
+ 
+   /* Pathname information */
+   int n_msgs;
+diff --git a/rfc822.c b/rfc822.c
+index b411f85..9c8e1a4 100644
+--- a/rfc822.c
++++ b/rfc822.c
+@@ -990,7 +990,7 @@ static void scan_status_flags(const char *s, struct headers *hdrs)/*{{{*/
+ 
+ /*{{{ data_to_rfc822() */
+ struct rfc822 *data_to_rfc822(struct msg_src *src,
+-    char *data, int length,
++    char *data, size_t length,
+     enum data_to_rfc822_error *error)
+ {
+   struct rfc822 *result;
+@@ -1265,7 +1265,7 @@ static struct ro_mapping *add_ro_cache(const char *filename, int fd, size_t len)
+ }
+ #endif /* USE_GZIP_MBOX || USE_BZIP_MBOX */
+ 
+-void create_ro_mapping(const char *filename, unsigned char **data, int *len)/*{{{*/
++void create_ro_mapping(const char *filename, unsigned char **data, size_t *len)/*{{{*/
+ {
+   struct stat sb;
+   int fd;
+@@ -1386,7 +1386,7 @@ comp_error:
+   data_alloc_type = ALLOC_MMAP;
+ }
+ /*}}}*/
+-void free_ro_mapping(unsigned char *data, int len)/*{{{*/
++void free_ro_mapping(unsigned char *data, size_t len)/*{{{*/
+ {
+   int r;
+ 
+@@ -1414,7 +1414,7 @@ static struct msg_src *setup_msg_src(char *filename)/*{{{*/
+ /*}}}*/
+ struct rfc822 *make_rfc822(char *filename)/*{{{*/
+ {
+-  int len;
++  size_t len;
+   unsigned char *data;
+   struct rfc822 *result;
+ 
+diff --git a/search.c b/search.c
+index 18b51ee..97967bc 100644
+--- a/search.c
++++ b/search.c
+@@ -681,7 +681,7 @@ static void mbox_terminate(const unsigned char *data, int len, FILE *out)/*{{{*/
+ static void append_file_to_mbox(const char *path, FILE *out)/*{{{*/
+ {
+   unsigned char *data;
+-  int len;
++  size_t len;
+   create_ro_mapping(path, &data, &len);
+   if (data) {
+     fprintf(out, "From mairix@mairix Mon Jan  1 12:34:56 1970\n");
+@@ -698,8 +698,8 @@ static int had_failed_checksum;
+ 
+ static void get_validated_mbox_msg(struct read_db *db, int msg_index,/*{{{*/
+                                    int *mbox_index,
+-                                   unsigned char **mbox_data, int *mbox_len,
+-                                   unsigned char **msg_data,  int *msg_len)
++                                   unsigned char **mbox_data, size_t *mbox_len,
++                                   unsigned char **msg_data,  size_t *msg_len)
+ {
+   /* msg_data==NULL if checksum mismatches */
+   unsigned char *start;
+@@ -738,7 +738,7 @@ static void append_mboxmsg_to_mbox(struct read_db *db, int msg_index, FILE *out)
+ {
+   /* Need to common up code with try_copy_to_path */
+   unsigned char *mbox_start, *msg_start;
+-  int mbox_len, msg_len;
++  size_t mbox_len, msg_len;
+   int mbox_index;
+ 
+   get_validated_mbox_msg(db, msg_index, &mbox_index, &mbox_start, &mbox_len, &msg_start, &msg_len);
+@@ -759,7 +759,7 @@ static void append_mboxmsg_to_mbox(struct read_db *db, int msg_index, FILE *out)
+ static void try_copy_to_path(struct read_db *db, int msg_index, char *target_path)/*{{{*/
+ {
+   unsigned char *data;
+-  int mbox_len, msg_len;
++  size_t mbox_len, msg_len;
+   int mbi;
+   FILE *out;
+   unsigned char *start;
+@@ -1214,7 +1214,7 @@ static int do_search(struct read_db *db, char **args, char *output_path, int sho
+                 unsigned int mbix, msgix;
+                 int start, len, after_end;
+                 unsigned char *mbox_start, *msg_start;
+-                int mbox_len, msg_len;
++                size_t mbox_len, msg_len;
+                 int mbox_index;
+ 
+                 start = db->mtime_table[i];
diff --git a/pkgs/tools/text/mark/default.nix b/pkgs/tools/text/mark/default.nix
new file mode 100644
index 00000000000..9c7f4e2b385
--- /dev/null
+++ b/pkgs/tools/text/mark/default.nix
@@ -0,0 +1,24 @@
+{ lib, buildGoModule, fetchFromGitHub }:
+
+buildGoModule rec {
+  pname = "mark";
+  version = "8.0";
+
+  src = fetchFromGitHub {
+    owner  = "kovetskiy";
+    repo   = "mark";
+    rev    = version;
+    sha256 = "sha256-1cJt/+OClc7YxSy9kGLQrREckjDvMIBdzet9SJGPb84=";
+  };
+
+  vendorSha256 = "sha256-a+pWSt24+aNABcLhiiFy+g/imBQtiqliAAWWkjPolxU=";
+
+  ldflags = [ "-s" "-w" "-X main.version=${version}" ];
+
+  meta = with lib; {
+    description = "A tool for syncing your markdown documentation with Atlassian Confluence pages";
+    homepage = "https://github.com/kovetskiy/mark";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ rguevara84 ];
+  };
+}
diff --git a/pkgs/tools/text/markdown-pp/default.nix b/pkgs/tools/text/markdown-pp/default.nix
new file mode 100644
index 00000000000..c6e937eab27
--- /dev/null
+++ b/pkgs/tools/text/markdown-pp/default.nix
@@ -0,0 +1,26 @@
+{ lib
+, fetchFromGitHub
+, python3
+}:
+
+python3.pkgs.buildPythonApplication rec {
+  pname = "MarkdownPP";
+  version = "1.5.1";
+  propagatedBuildInputs = with python3.pkgs; [ pillow watchdog ];
+  checkPhase = ''
+    cd test
+    PATH=$out/bin:$PATH ${python3}/bin/${python3.executable} test.py
+  '';
+  src = fetchFromGitHub {
+    owner = "jreese";
+    repo = "markdown-pp";
+    rev = "v${version}";
+    sha256 = "180i5wn9z6vdk2k2bh8345z3g80hj7zf5s2pq0h7k9vaxqpp7avc";
+  };
+  meta = with lib; {
+    description = "Preprocessor for Markdown files to generate a table of contents and other documentation needs";
+    license = licenses.mit;
+    homepage = "https://github.com/jreese/markdown-pp";
+    maintainers = with maintainers; [ zgrannan ];
+  };
+}
diff --git a/pkgs/tools/text/mawk/default.nix b/pkgs/tools/text/mawk/default.nix
new file mode 100644
index 00000000000..62a23318ca2
--- /dev/null
+++ b/pkgs/tools/text/mawk/default.nix
@@ -0,0 +1,22 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "mawk";
+  version = "1.3.4-20200120";
+
+  src = fetchurl {
+    urls = [
+      "ftp://ftp.invisible-island.net/mawk/mawk-${version}.tgz"
+      "https://invisible-mirror.net/archives/mawk/mawk-${version}.tgz"
+    ];
+    sha256 = "0dw2icf8bnqd9y0clfd9pkcxz4b2phdihwci13z914mf3wgcvm3z";
+  };
+
+  meta = with lib; {
+    description = "Interpreter for the AWK Programming Language";
+    homepage = "https://invisible-island.net/mawk/mawk.html";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [ ehmry ];
+    platforms = with platforms; unix;
+  };
+}
diff --git a/pkgs/tools/text/mb2md/default.nix b/pkgs/tools/text/mb2md/default.nix
new file mode 100644
index 00000000000..78ce7f59397
--- /dev/null
+++ b/pkgs/tools/text/mb2md/default.nix
@@ -0,0 +1,38 @@
+{ lib, stdenv, fetchurl, makeWrapper, perlPackages }:
+
+let
+  perlDeps = with perlPackages; [ TimeDate ];
+in
+stdenv.mkDerivation rec {
+  version = "3.20";
+  pname = "mb2md";
+
+  src = fetchurl {
+    url = "http://batleth.sapienti-sat.org/projects/mb2md/mb2md-${version}.pl.gz";
+    sha256 = "0bvkky3c90738h3skd2f1b2yy5xzhl25cbh9w2dy97rs86ssjidg";
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+  buildInputs = [ perlPackages.perl ];
+
+  unpackPhase = ''
+    sourceRoot=.
+    gzip -d < $src > mb2md.pl
+  '';
+
+  installPhase = ''
+    install -D $sourceRoot/mb2md.pl $out/bin/mb2md
+  '';
+
+  postFixup = ''
+    wrapProgram $out/bin/mb2md \
+      --set PERL5LIB "${perlPackages.makePerlPath perlDeps}"
+  '';
+
+  meta = with lib; {
+    description = "mbox to maildir tool";
+    license = licenses.publicDomain;
+    platforms = platforms.all;
+    maintainers = [ maintainers.jb55 ];
+  };
+}
diff --git a/pkgs/tools/text/mdbook-graphviz/default.nix b/pkgs/tools/text/mdbook-graphviz/default.nix
new file mode 100644
index 00000000000..353c2b99ee9
--- /dev/null
+++ b/pkgs/tools/text/mdbook-graphviz/default.nix
@@ -0,0 +1,26 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, CoreServices, graphviz }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "mdbook-graphviz";
+  version = "0.1.4";
+
+  src = fetchFromGitHub {
+    owner = "dylanowen";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-HTHGb23wc10iAWXX/TNMXjTLWm+OSf1WWW1+/aQRcsk=";
+  };
+
+  cargoSha256 = "sha256-7z/4brKY9vpic8mv1b4P/8DE+VyColYnPPoPmY9891M=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ CoreServices ];
+
+  checkInputs = [ graphviz ];
+
+  meta = with lib; {
+    description = "A preprocessor for mdbook, rendering Graphviz graphs to HTML at build time.";
+    homepage = "https://github.com/dylanowen/mdbook-graphviz";
+    license = [ licenses.mpl20 ];
+    maintainers = with maintainers; [ lovesegfault ];
+  };
+}
diff --git a/pkgs/tools/text/mdbook-katex/default.nix b/pkgs/tools/text/mdbook-katex/default.nix
new file mode 100644
index 00000000000..a97e7ca8948
--- /dev/null
+++ b/pkgs/tools/text/mdbook-katex/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, CoreServices }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "mdbook-katex";
+  version = "0.2.10";
+
+  src = fetchFromGitHub {
+    owner = "lzanini";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-5PzXX7icRxcHpzjp3x/9ssn2o0444uHrzBn1Ds1DEPM=";
+  };
+
+  cargoSha256 = "sha256-tqdpIBlKiyYSWFPYTnzVeDML2GM+mukbOHS3sNYUgdc=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ CoreServices ];
+
+  meta = with lib; {
+    description = "A preprocessor for mdbook, rendering LaTeX equations to HTML at build time.";
+    homepage = "https://github.com/lzanini/${pname}";
+    license = [ licenses.mit ];
+    maintainers = with maintainers; [ lovesegfault ];
+  };
+}
diff --git a/pkgs/tools/text/mdbook-linkcheck/default.nix b/pkgs/tools/text/mdbook-linkcheck/default.nix
new file mode 100644
index 00000000000..b37b16876b0
--- /dev/null
+++ b/pkgs/tools/text/mdbook-linkcheck/default.nix
@@ -0,0 +1,33 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, pkg-config, openssl, Security
+, testVersion, mdbook-linkcheck }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "mdbook-linkcheck";
+  version = "0.7.6";
+
+  src = fetchFromGitHub {
+    owner = "Michael-F-Bryan";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-ZEOuA8W05800cnArscaGGOWTgzU6V3/wJiQcSx1MVkY=";
+  };
+
+  cargoSha256 = "sha256-EtPhbKvPHSnmPXemCzOXujlqqfdDSFaJpcZVJoHQq6U=";
+
+  buildInputs = if stdenv.isDarwin then [ Security ] else [ openssl ];
+
+  nativeBuildInputs = lib.optionals (!stdenv.isDarwin) [ pkg-config ];
+
+  OPENSSL_NO_VENDOR = 1;
+
+  doCheck = false; # tries to access network to test broken web link functionality
+
+  passthru.tests.version = testVersion { package = mdbook-linkcheck; };
+
+  meta = with lib; {
+    description = "A backend for `mdbook` which will check your links for you.";
+    homepage = "https://github.com/Michael-F-Bryan/mdbook-linkcheck";
+    license = licenses.mit;
+    maintainers = with maintainers; [ zhaofengli ];
+  };
+}
diff --git a/pkgs/tools/text/mdbook-mermaid/default.nix b/pkgs/tools/text/mdbook-mermaid/default.nix
new file mode 100644
index 00000000000..05bf89e3018
--- /dev/null
+++ b/pkgs/tools/text/mdbook-mermaid/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, CoreServices }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "mdbook-mermaid";
+  version = "0.10.0";
+
+  src = fetchFromGitHub {
+    owner = "badboy";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-dXeu/e92lafurA/bqKoszIjK/3qw/ZvVKnDxYALRpTk=";
+  };
+
+  cargoSha256 = "sha256-LVfeQPRpwv1l3Brm8HJYoYvv26fJhsfR4I9Ds4NuWQM=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ CoreServices ];
+
+  meta = with lib; {
+    description = "A preprocessor for mdbook to add mermaid.js support";
+    homepage = "https://github.com/badboy/mdbook-mermaid";
+    license = [ licenses.mpl20 ];
+    maintainers = with maintainers; [ xrelkd ];
+  };
+}
diff --git a/pkgs/tools/text/mdbook-plantuml/default.nix b/pkgs/tools/text/mdbook-plantuml/default.nix
new file mode 100644
index 00000000000..0b26bee0953
--- /dev/null
+++ b/pkgs/tools/text/mdbook-plantuml/default.nix
@@ -0,0 +1,28 @@
+{ lib, fetchFromGitHub, stdenv, rustPlatform, darwin, pkg-config, openssl
+, libiconv, CoreServices }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "mdbook-plantuml";
+  version = "0.7.0";
+
+  src = fetchFromGitHub {
+    owner = "sytsereitsma";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "1m53sp3k387injn6mwk2c6rkzw16b12m4j7q0p69fdb3fiqbkign";
+  };
+
+  cargoSha256 = "0xi14k86ym3rfz6901lmj444y814m7vp90bwsyjmcph3hdv6mjp0";
+
+  nativeBuildInputs = [ pkg-config ];
+
+  buildInputs = [ openssl ]
+    ++ lib.optionals stdenv.isDarwin [ CoreServices ];
+
+  meta = with lib; {
+    description = "mdBook preprocessor to render PlantUML diagrams to png images in the book output directory";
+    homepage = "https://github.com/sytsereitsma/mdbook-plantuml";
+    license = [ licenses.mit ];
+    maintainers = with maintainers; [ jcouyang ];
+  };
+}
diff --git a/pkgs/tools/text/mdbook/default.nix b/pkgs/tools/text/mdbook/default.nix
new file mode 100644
index 00000000000..d3a136d6bf7
--- /dev/null
+++ b/pkgs/tools/text/mdbook/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, CoreServices }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "mdbook";
+  version = "0.4.12";
+
+  src = fetchFromGitHub {
+    owner = "rust-lang";
+    repo = "mdBook";
+    rev = "v${version}";
+    sha256 = "sha256-2lxotwL3Dc9jRA12iKO5zotO80pa+RfUZucyDRgFOsI=";
+  };
+
+  cargoSha256 = "sha256-TNd4pj4qSKgmmVtSCSKFCxNtv96xD7+24BPsLXPgiEI=";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ CoreServices ];
+
+  meta = with lib; {
+    description = "Create books from MarkDown";
+    homepage = "https://github.com/rust-lang/mdBook";
+    license = [ licenses.mpl20 ];
+    maintainers = [ maintainers.havvy ];
+  };
+}
diff --git a/pkgs/tools/text/mdcat/default.nix b/pkgs/tools/text/mdcat/default.nix
new file mode 100644
index 00000000000..f6dcd72d7bf
--- /dev/null
+++ b/pkgs/tools/text/mdcat/default.nix
@@ -0,0 +1,57 @@
+{ lib
+, stdenv
+, fetchFromGitea
+, rustPlatform
+, pkg-config
+, asciidoctor
+, openssl
+, Security
+, ansi2html
+, installShellFiles
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "mdcat";
+  version = "0.26.1";
+
+  src = fetchFromGitea {
+    domain = "codeberg.org";
+    owner = "flausch";
+    repo = "mdcat";
+    rev = "mdcat-${version}";
+    sha256 = "sha256-vB49EwQltonR9Uw8RRMZTPR4WkcylnIqiE0/8+t2R1Q=";
+  };
+
+  nativeBuildInputs = [ pkg-config asciidoctor installShellFiles ];
+  buildInputs = [ openssl ]
+    ++ lib.optional stdenv.isDarwin Security;
+
+  cargoSha256 = "sha256-v52ob5l5HiiZZmo88D9/ldFi0170/BuPzgKIt9ctSgU=";
+
+  checkInputs = [ ansi2html ];
+  # Skip tests that use the network and that include files.
+  checkFlags = [
+    "--skip magic::tests::detect_mimetype_of_larger_than_magic_param_bytes_max_length"
+    "--skip magic::tests::detect_mimetype_of_magic_param_bytes_max_length"
+    "--skip magic::tests::detect_mimetype_of_png_image"
+    "--skip magic::tests::detect_mimetype_of_svg_image"
+    "--skip resources::tests::read_url_with_http_url_fails_when_size_limit_is_exceeded"
+    "--skip resources::tests::read_url_with_http_url_fails_when_status_404"
+    "--skip resources::tests::read_url_with_http_url_returns_content_when_status_200"
+    "--skip iterm2_tests_render_md_samples_images_md"
+  ];
+
+  postInstall = ''
+    installManPage $releaseDir/build/mdcat-*/out/mdcat.1
+    installShellCompletion --bash $releaseDir/build/mdcat-*/out/completions/mdcat.bash
+    installShellCompletion --fish $releaseDir/build/mdcat-*/out/completions/mdcat.fish
+    installShellCompletion --zsh $releaseDir/build/mdcat-*/out/completions/_mdcat
+  '';
+
+  meta = with lib; {
+    description = "cat for markdown";
+    homepage = "https://github.com/lunaryorn/mdcat";
+    license = with licenses; [ mpl20 ];
+    maintainers = with maintainers; [ davidtwco SuperSandro2000 ];
+  };
+}
diff --git a/pkgs/tools/text/mecab/base.nix b/pkgs/tools/text/mecab/base.nix
new file mode 100644
index 00000000000..181eb405cbd
--- /dev/null
+++ b/pkgs/tools/text/mecab/base.nix
@@ -0,0 +1,16 @@
+{ fetchurl }:
+
+{
+    version = "0.996";
+
+    src = fetchurl {
+      url = "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE";
+      name = "mecab-0.996.tar.gz";
+      sha256 = "0ncwlqxl1hdn1x4v4kr2sn1sbbcgnhdphp0lcvk74nqkhdbk4wz0";
+    };
+
+    buildPhase = ''
+      make
+      make check
+    '';
+}
diff --git a/pkgs/tools/text/mecab/default.nix b/pkgs/tools/text/mecab/default.nix
new file mode 100644
index 00000000000..04293d29efb
--- /dev/null
+++ b/pkgs/tools/text/mecab/default.nix
@@ -0,0 +1,21 @@
+{ lib, stdenv, fetchurl, mecab-ipadic }:
+
+let
+  mecab-base = import ./base.nix { inherit fetchurl; };
+in
+stdenv.mkDerivation (mecab-base // {
+    pname = "mecab";
+    version = mecab-base.version;
+
+    postInstall = ''
+      sed -i 's|^dicdir = .*$|dicdir = ${mecab-ipadic}|' "$out/etc/mecabrc"
+    '';
+
+    meta = with lib; {
+      description = "Japanese morphological analysis system";
+      homepage = "http://taku910.github.io/mecab/";
+      license = licenses.bsd3;
+      platforms = platforms.unix;
+      maintainers = with maintainers; [ auntie ];
+    };
+})
diff --git a/pkgs/tools/text/mecab/ipadic.nix b/pkgs/tools/text/mecab/ipadic.nix
new file mode 100644
index 00000000000..026e385e7c2
--- /dev/null
+++ b/pkgs/tools/text/mecab/ipadic.nix
@@ -0,0 +1,18 @@
+{ stdenv, fetchurl, mecab-nodic }:
+
+stdenv.mkDerivation {
+  pname = "mecab-ipadic";
+  version = "2.7.0-20070801";
+
+  src = fetchurl {
+    url = "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7MWVlSDBCSXZMTXM";
+    name = "mecab-ipadic-2.7.0-20070801.tar.gz";
+    sha256 = "08rmkvj0f0x6jq0axrjw2y5nam0mavv6x77dp9v4al0wi1ym4bxn";
+  };
+
+  buildInputs = [ mecab-nodic ];
+
+  configurePhase = ''
+    ./configure --with-dicdir="$out"
+  '';
+}
diff --git a/pkgs/tools/text/mecab/nodic.nix b/pkgs/tools/text/mecab/nodic.nix
new file mode 100644
index 00000000000..be9003623e0
--- /dev/null
+++ b/pkgs/tools/text/mecab/nodic.nix
@@ -0,0 +1,9 @@
+{ stdenv, fetchurl }:
+
+let
+  mecab-base = import ./base.nix { inherit fetchurl; };
+in
+stdenv.mkDerivation (mecab-base // {
+    pname = "mecab-nodic";
+    version = mecab-base.version;
+})
diff --git a/pkgs/tools/text/miller/default.nix b/pkgs/tools/text/miller/default.nix
new file mode 100644
index 00000000000..f64f195db95
--- /dev/null
+++ b/pkgs/tools/text/miller/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, autoreconfHook, flex, libtool }:
+
+stdenv.mkDerivation rec {
+  pname = "miller";
+
+  version = "5.10.3";
+
+  src = fetchFromGitHub {
+    owner = "johnkerl";
+    repo = "miller";
+    rev = "v${version}";
+    sha256 = "sha256-Mag7bIfZNdp+sM54yKp8HdH3kWjwWRfyPBGthej2jd8=";
+  };
+
+  nativeBuildInputs = [ autoreconfHook flex libtool ];
+
+  meta = with lib; {
+    description = "Like awk, sed, cut, join, and sort for name-indexed data such as CSV, TSV, and tabular JSON";
+    homepage    = "http://johnkerl.org/miller/";
+    license     = licenses.bsd2;
+    maintainers = with maintainers; [ mstarzyk ];
+    platforms   = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/mir-qualia/default.nix b/pkgs/tools/text/mir-qualia/default.nix
new file mode 100644
index 00000000000..f532daf8c44
--- /dev/null
+++ b/pkgs/tools/text/mir-qualia/default.nix
@@ -0,0 +1,21 @@
+{ lib, pythonPackages, fetchurl }:
+
+pythonPackages.buildPythonApplication rec {
+  pname = "mir.qualia";
+  version = "2.0.0";
+  doCheck = false; # 2.0.0-released pytests are broken
+
+  buildInputs = with pythonPackages; [ pytest ];
+
+  src = fetchurl {
+    url = "mirror://pypi/m/mir.qualia/mir.qualia-${version}.tar.gz";
+    sha256 = "1ybq6jb5clh9hw0sp3idp4hjv2gkm9yiaph48gcc208affflc8m9";
+  };
+
+  meta = {
+    description = "Dynamically enable sections of config files";
+    homepage = "https://github.com/darkfeline/mir.qualia";
+    license = lib.licenses.asl20;
+    maintainers = [ lib.maintainers.srhb ] ;
+  };
+}
diff --git a/pkgs/tools/text/mmdoc/default.nix b/pkgs/tools/text/mmdoc/default.nix
new file mode 100644
index 00000000000..e30020d15d9
--- /dev/null
+++ b/pkgs/tools/text/mmdoc/default.nix
@@ -0,0 +1,37 @@
+{ lib
+, stdenv
+, fetchFromGitHub
+, cmark-gfm
+, xxd
+, fastJson
+, libzip
+, ninja
+, meson
+, pkg-config
+}:
+
+stdenv.mkDerivation rec {
+  pname = "mmdoc";
+  version = "0.9.1";
+
+  src = fetchFromGitHub {
+    owner = "ryantm";
+    repo = "mmdoc";
+    rev = version;
+    hash = "sha256-Lz2+vsXjz9BVOCI1vIrNTvZgh19OuvXEhnMw2QBZr1w=";
+  };
+
+  nativeBuildInputs = [ ninja meson pkg-config xxd ];
+
+  buildInputs = [ cmark-gfm fastJson libzip ];
+
+  doCheck = stdenv.isx86_64;
+
+  meta = with lib; {
+    description = "Minimal Markdown Documentation";
+    homepage = "https://github.com/ryantm/mmdoc";
+    license = licenses.cc0;
+    maintainers = with maintainers; [ ryantm ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/morsel/default.nix b/pkgs/tools/text/morsel/default.nix
new file mode 100644
index 00000000000..3968eb2cc4a
--- /dev/null
+++ b/pkgs/tools/text/morsel/default.nix
@@ -0,0 +1,22 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "morsel";
+  version = "0.1.0";
+
+  src = fetchFromGitHub {
+    owner = "SamLee514";
+    repo = "morsel";
+    rev = "v${version}";
+    sha256 = "sha256-m4bCni/9rMTPhZSogpd5+ARrW11TPHSvQpdz3wUr9H4=";
+  };
+
+  cargoSha256 = "sha256-2xR2/013ocDKWS1oWitpAbSDPRwEJJqFcCIm6ZQpCoc=";
+
+  meta = with lib; {
+    description = "Command line tool to translate morse code input to text in real time";
+    homepage = "https://github.com/SamLee514/morsel";
+    license = licenses.mit;
+    maintainers = with maintainers; [ siraben ];
+  };
+}
diff --git a/pkgs/tools/text/mpage/default.nix b/pkgs/tools/text/mpage/default.nix
new file mode 100644
index 00000000000..b48f89d6618
--- /dev/null
+++ b/pkgs/tools/text/mpage/default.nix
@@ -0,0 +1,32 @@
+{ fetchurl, lib, stdenv }:
+
+stdenv.mkDerivation rec {
+  pname = "mpage";
+  version = "2.5.7";
+
+  src = fetchurl {
+    url = "https://www.mesa.nl/pub/mpage/mpage-${version}.tgz";
+    sha256 = "1zn37r5xrvjgjbw2bdkc0r7s6q8b1krmcryzj0yf0dyxbx79rasi";
+  };
+
+  postPatch = ''
+    sed -i "Makefile" -e "s|^ *PREFIX *=.*$|PREFIX = $out|g"
+    substituteInPlace Makefile --replace 'gcc' '${stdenv.cc.targetPrefix}cc'
+  '';
+
+  meta = {
+    description = "Many-to-one page printing utility";
+
+    longDescription = ''
+      Mpage reads plain text files or PostScript documents and prints
+      them on a PostScript printer with the text reduced in size so
+      that several pages appear on one sheet of paper.  This is useful
+      for viewing large printouts on a small amount of paper.  It uses
+      ISO 8859.1 to print 8-bit characters.
+    '';
+
+    license = "liberal";  # a non-copyleft license, see `Copyright' file
+    homepage = "http://www.mesa.nl/pub/mpage/";
+    platforms = lib.platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/multitran/data/default.nix b/pkgs/tools/text/multitran/data/default.nix
new file mode 100644
index 00000000000..bfc148df782
--- /dev/null
+++ b/pkgs/tools/text/multitran/data/default.nix
@@ -0,0 +1,27 @@
+{lib, stdenv, fetchurl} :
+
+# This package requires a locale ru_RU.cp1251 locale entry.
+# Waiting for a better idea, I created it modifying a store file using:
+#   localedef -f CP1251 -i ru_RU ru_RU.CP1251
+# The store file mentioned is in "${glibc.out}/lib/locale/locale-archive"
+
+stdenv.mkDerivation {
+  pname = "multitran-data";
+  version = "0.3";
+
+  src = fetchurl {
+      url = "mirror://sourceforge/multitran/multitran-data.tar.bz2";
+      sha256 = "9c2ff5027c2fe72b0cdf056311cd7543f447feb02b455982f20d4a3966b7828c";
+  };
+
+  patchPhase = ''
+    sed -i -e 's@\$(DESTDIR)/usr@'$out'@' Makefile
+  '';
+
+  meta = {
+    homepage = "http://multitran.sourceforge.net/";
+    description = "Multitran data english-russian";
+    license = lib.licenses.gpl2;
+    platforms = lib.platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/multitran/libbtree/default.nix b/pkgs/tools/text/multitran/libbtree/default.nix
new file mode 100644
index 00000000000..91c4bb0ea7f
--- /dev/null
+++ b/pkgs/tools/text/multitran/libbtree/default.nix
@@ -0,0 +1,21 @@
+{lib, stdenv, fetchurl} :
+
+stdenv.mkDerivation rec {
+  pname = "libbtree";
+  version = "0.0.1alpha2";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/multitran/libbtree-${version}.tar.bz2";
+    sha256 = "34a584e45058950337ff9342693b6739b52c3ce17e66440526c4bd6f9575802c";
+  };
+  patchPhase = ''
+    sed -i -e 's@\$(DESTDIR)/usr@'$out'@' src/Makefile;
+  '';
+
+  meta = {
+    homepage = "http://multitran.sourceforge.net/";
+    description = "Multitran lib: library for reading Multitran's BTREE database format";
+    license = lib.licenses.gpl2;
+    platforms = lib.platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/multitran/libfacet/default.nix b/pkgs/tools/text/multitran/libfacet/default.nix
new file mode 100644
index 00000000000..0e6dd0d6e65
--- /dev/null
+++ b/pkgs/tools/text/multitran/libfacet/default.nix
@@ -0,0 +1,26 @@
+{ lib, stdenv, fetchurl, libmtsupport }:
+
+stdenv.mkDerivation rec {
+  pname = "libfacet";
+  version = "0.0.1alpha2";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/multitran/libfacet-${version}.tar.bz2";
+    sha256 = "dc53351c4035a3c27dc6c1d0410e808346fbc107e7e7c112ec65c59d0df7a144";
+  };
+
+  buildInputs = [ libmtsupport ];
+
+  patchPhase = ''
+    sed -i -e 's@\$(DESTDIR)/usr@'$out'@' \
+      -e 's@/usr/include/mt/support@${libmtsupport}/include/mt/support@' \
+      src/Makefile;
+  '';
+
+  meta = {
+    homepage = "http://multitran.sourceforge.net/";
+    description = "Multitran lib: enchanced locale facets";
+    license = lib.licenses.gpl2;
+    platforms = lib.platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/multitran/libmtquery/default.nix b/pkgs/tools/text/multitran/libmtquery/default.nix
new file mode 100644
index 00000000000..5cc8e724e71
--- /dev/null
+++ b/pkgs/tools/text/multitran/libmtquery/default.nix
@@ -0,0 +1,31 @@
+{lib, stdenv, fetchurl, libmtsupport, libfacet, libbtree, multitrandata } :
+
+stdenv.mkDerivation rec {
+  pname = "libmtquery";
+  version = "0.0.1alpha3";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/multitran/libmtquery-${version}.tar.bz2";
+    sha256 = "e24c7c15772445f1b14871928d84dd03cf93bd88f9d2b2ed1bf0257c2cf2b15e";
+  };
+
+  buildInputs = [ libmtsupport libfacet libbtree multitrandata ];
+
+  NIX_LDFLAGS = "-lbtree";
+
+  patchPhase = ''
+    sed -i -e 's@\$(DESTDIR)/usr@'$out'@' \
+      -e 's@/usr/include/mt/support@${libmtsupport}/include/mt/support@' \
+      -e 's@/usr/include/btree@${libbtree}/include/btree@' \
+      -e 's@/usr/include/facet@${libfacet}/include/facet@' \
+      src/Makefile testsuite/Makefile;
+    sed -i -e 's@/usr/share/multitran@${multitrandata}/share/multitran@' src/config.cc
+  '';
+
+  meta = {
+    homepage = "http://multitran.sourceforge.net/";
+    description = "Multitran lib: main engine to query translations";
+    license = lib.licenses.gpl2;
+    platforms = lib.platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/multitran/libmtsupport/default.nix b/pkgs/tools/text/multitran/libmtsupport/default.nix
new file mode 100644
index 00000000000..454709b8eb7
--- /dev/null
+++ b/pkgs/tools/text/multitran/libmtsupport/default.nix
@@ -0,0 +1,21 @@
+{lib, stdenv, fetchurl} :
+
+stdenv.mkDerivation rec {
+  pname = "libmtsupport";
+  version = "0.0.1alpha2";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/multitran/libmtsupport-${version}.tar.bz2";
+    sha256 = "481f0f1ec15d7274f1e4eb93e7d060df10a181efd037eeff5e8056d283a9298b";
+  };
+  patchPhase = ''
+    sed -i -e 's@\$(DESTDIR)/usr@'$out'@' src/Makefile;
+  '';
+
+  meta = {
+    homepage = "http://multitran.sourceforge.net/";
+    description = "Multitran lib: basic useful functions";
+    license = lib.licenses.gpl2;
+    platforms = lib.platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/multitran/mtutils/default.nix b/pkgs/tools/text/multitran/mtutils/default.nix
new file mode 100644
index 00000000000..2428caada5b
--- /dev/null
+++ b/pkgs/tools/text/multitran/mtutils/default.nix
@@ -0,0 +1,34 @@
+{lib, stdenv, fetchurl, libmtsupport, libfacet, libbtree, libmtquery, help2man} :
+
+stdenv.mkDerivation rec {
+  pname = "mt-utils";
+  version = "0.0.1alpha3";
+
+  src = fetchurl {
+      url = "mirror://sourceforge/multitran/mt-utils-${version}.tar.bz2";
+      sha256 = "e407702c90c5272882386914e1eeca5f6c5039393af9a44538536b94867b0a0e";
+  };
+
+  buildInputs = [ libmtsupport libfacet libbtree libmtquery help2man ];
+
+  patchPhase = ''
+    sed -i -e 's@\$(DESTDIR)/usr@'$out'@' \
+      -e 's@/usr/include/mt/support@${libmtsupport}/include/mt/support@' \
+      -e 's@/usr/include/btree@${libbtree}/include/btree@' \
+      -e 's@/usr/include/facet@${libfacet}/include/facet@' \
+      -e 's@/usr/include/mt/query@${libmtquery}/include/mt/query@' \
+      -e 's@-lmtquery@-lmtquery -lmtsupport -lfacet@' \
+      src/Makefile;
+    # Fixing multibyte locale output
+    sed -i -e 's@message.length()@message.length()*5@' \
+      src/converter.cc;
+  '';
+
+  meta = {
+    homepage = "http://multitran.sourceforge.net/";
+    description = "Multitran: simple command line utilities for dictionary maintenance";
+    license = lib.licenses.gpl2;
+    maintainers = with lib.maintainers; [viric];
+    platforms = with lib.platforms; linux;
+  };
+}
diff --git a/pkgs/tools/text/namazu/default.nix b/pkgs/tools/text/namazu/default.nix
new file mode 100644
index 00000000000..e748515b051
--- /dev/null
+++ b/pkgs/tools/text/namazu/default.nix
@@ -0,0 +1,34 @@
+{ fetchurl, lib, stdenv, perl, perlPackages, makeWrapper }:
+
+stdenv.mkDerivation rec {
+  pname = "namazu";
+  version = "2.0.21";
+
+  src = fetchurl {
+    url = "http://namazu.org/stable/${pname}-${version}.tar.gz";
+    sha256 = "1xvi7hrprdchdpzhg3fvk4yifaakzgydza5c0m50h1yvg6vay62w";
+  };
+
+  buildInputs = [ perl perlPackages.FileMMagic ];
+  nativeBuildInputs = [ makeWrapper ];
+
+  postInstall = ''
+    wrapProgram $out/bin/mknmz --set PERL5LIB ${perlPackages.makeFullPerlPath [ perlPackages.FileMMagic ]}
+  '';
+
+  meta = {
+    description = "Full-text search engine";
+
+    longDescription = ''
+      Namazu is a full-text search engine intended for easy use.  Not
+      only does it work as a small or medium scale Web search engine,
+      but also as a personal search system for email or other files.
+    '';
+
+    license = lib.licenses.gpl2Plus;
+    homepage = "http://namazu.org/";
+
+    platforms = lib.platforms.gnu ++ lib.platforms.linux;  # arbitrary choice
+    maintainers = [ ];
+  };
+}
diff --git a/pkgs/tools/text/nawk/default.nix b/pkgs/tools/text/nawk/default.nix
new file mode 100644
index 00000000000..580d30a5833
--- /dev/null
+++ b/pkgs/tools/text/nawk/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, fetchFromGitHub, bison, buildPackages }:
+
+stdenv.mkDerivation rec {
+  pname = "nawk";
+  version = "unstable-2021-02-15";
+
+  src = fetchFromGitHub {
+    owner = "onetrueawk";
+    repo = "awk";
+    rev = "c0f4e97e4561ff42544e92512bbaf3d7d1f6a671";
+    sha256 = "kQCvItpSJnDJMDvlB8ruY+i0KdjmAphRDqCKw8f0m/8=";
+  };
+
+  depsBuildBuild = [ buildPackages.stdenv.cc ];
+  nativeBuildInputs = [ bison ];
+  makeFlags = [
+    "CC=${stdenv.cc.targetPrefix}cc"
+    "HOSTCC=${if stdenv.buildPlatform.isDarwin then "clang" else "cc"}"
+  ];
+
+  installPhase = ''
+    runHook preInstall
+    install -Dm755 a.out "$out/bin/nawk"
+    install -Dm644 awk.1 "$out/share/man/man1/nawk.1"
+    runHook postInstall
+  '';
+
+  meta = {
+    description = "The one, true implementation of AWK";
+    longDescription = ''
+       This is the version of awk described in "The AWK Programming
+       Language", by Al Aho, Brian Kernighan, and Peter Weinberger
+       (Addison-Wesley, 1988, ISBN 0-201-07981-X).
+    '';
+    homepage = "https://www.cs.princeton.edu/~bwk/btl.mirror/";
+    license = lib.licenses.mit;
+    maintainers = [ lib.maintainers.konimex ];
+    platforms = lib.platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/nkf/default.nix b/pkgs/tools/text/nkf/default.nix
new file mode 100644
index 00000000000..a2b5f66a6e9
--- /dev/null
+++ b/pkgs/tools/text/nkf/default.nix
@@ -0,0 +1,21 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "nkf";
+  version = "2.1.5";
+
+  src = fetchurl {
+    url = "mirror://osdn/nkf/70406/${pname}-${version}.tar.gz";
+    sha256 = "0i5dbcb9aipwr8ym4mhvgf1in3frl6y8h8x96cprz9s7b11xz9yi";
+  };
+
+  makeFlags = [ "prefix=$(out)" ];
+
+  meta = {
+    description = "Tool for converting encoding of Japanese text";
+    homepage = "https://nkf.osdn.jp/";
+    license = lib.licenses.zlib;
+    platforms = lib.platforms.unix;
+    maintainers = [ lib.maintainers.auntie ];
+  };
+}
diff --git a/pkgs/tools/text/num-utils/default.nix b/pkgs/tools/text/num-utils/default.nix
new file mode 100644
index 00000000000..14784a4e8cf
--- /dev/null
+++ b/pkgs/tools/text/num-utils/default.nix
@@ -0,0 +1,29 @@
+{ lib, stdenv, fetchurl, perl }:
+
+stdenv.mkDerivation rec {
+  pname = "num-utils";
+  version = "0.5";
+
+  src = fetchurl {
+    url = "https://suso.suso.org/programs/num-utils/downloads/num-utils-${version}.tar.gz";
+    sha256 = "0kn6yskjww2agcqvas5l2xp55mp4njdxqkdicchlji3qzih2fn83";
+  };
+
+  buildInputs = [ perl ];
+
+  patchPhase = ''
+    substituteInPlace Makefile --replace "-o 0 -g 0" "" --replace "\$(RPMDIR)" ""
+  '';
+  makeFlags = [
+    "TOPDIR=${placeholder "out"}"
+    "PERL=${perl}/bin/perl"
+  ];
+
+  meta = with lib; {
+    description = "Programs for dealing with numbers from the command line";
+    homepage = "https://suso.suso.org/xulu/Num-utils";
+    license = licenses.gpl2Plus;
+    platforms = platforms.all;
+    maintainers = [ maintainers.catern ];
+  };
+}
diff --git a/pkgs/tools/text/numdiff/default.nix b/pkgs/tools/text/numdiff/default.nix
new file mode 100644
index 00000000000..317d29003cd
--- /dev/null
+++ b/pkgs/tools/text/numdiff/default.nix
@@ -0,0 +1,26 @@
+{ lib, stdenv, fetchurl, libintl }:
+
+
+stdenv.mkDerivation rec {
+  pname = "numdiff";
+  version = "5.9.0";
+
+  src = fetchurl {
+    url = "mirror://savannah/numdiff/numdiff-${version}.tar.gz";
+    sha256 = "1vzmjh8mhwwysn4x4m2vif7q2k8i19x8azq7pzmkwwj4g48lla47";
+  };
+
+  buildInputs = [ libintl ];
+
+  meta = with lib; {
+    description = ''
+      A little program that can be used to compare putatively similar files
+      line by line and field by field, ignoring small numeric differences
+      or/and different numeric formats
+    '';
+    homepage = "https://www.nongnu.org/numdiff/";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/odt2txt/default.nix b/pkgs/tools/text/odt2txt/default.nix
new file mode 100644
index 00000000000..0eb18e8435d
--- /dev/null
+++ b/pkgs/tools/text/odt2txt/default.nix
@@ -0,0 +1,23 @@
+{ lib, stdenv, fetchurl, zlib, libiconv }:
+
+stdenv.mkDerivation rec {
+  pname = "odt2txt";
+  version = "0.5";
+
+  src = fetchurl {
+    url = "${meta.homepage}/archive/v${version}.tar.gz";
+    sha256 = "23a889109ca9087a719c638758f14cc3b867a5dcf30a6c90bf6a0985073556dd";
+  };
+
+  configurePhase="export makeFlags=\"DESTDIR=$out\"";
+
+  buildInputs = [ zlib libiconv ];
+
+  meta = {
+    description = "Simple .odt to .txt converter";
+    homepage = "https://github.com/dstosberg/odt2txt";
+    platforms = lib.platforms.all;
+    license = lib.licenses.gpl2;
+    maintainers = [ ];
+  };
+}
diff --git a/pkgs/tools/text/opencc/default.nix b/pkgs/tools/text/opencc/default.nix
new file mode 100644
index 00000000000..5ad14295e87
--- /dev/null
+++ b/pkgs/tools/text/opencc/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, fetchFromGitHub, cmake, python2 }:
+
+stdenv.mkDerivation rec {
+  pname = "opencc";
+  version = "1.1.3";
+
+  src = fetchFromGitHub {
+    owner = "BYVoid";
+    repo = "OpenCC";
+    rev = "ver.${version}";
+    sha256 = "sha256-q/y4tRov/BYCAiE4i7fT6ysTerxxOHMZUWT2Jlo/0rI=";
+  };
+
+  nativeBuildInputs = [ cmake python2 ];
+
+  # let intermediate tools find intermediate library
+  preBuild = lib.optionalString stdenv.isLinux ''
+    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}$(pwd)/src
+  '' + lib.optionalString stdenv.isDarwin ''
+    export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH''${DYLD_LIBRARY_PATH:+:}$(pwd)/src
+  '';
+
+  meta = with lib; {
+    homepage = "https://github.com/BYVoid/OpenCC";
+    license = licenses.asl20;
+    description = "A project for conversion between Traditional and Simplified Chinese";
+    longDescription = ''
+      Open Chinese Convert (OpenCC) is an opensource project for conversion between
+      Traditional Chinese and Simplified Chinese, supporting character-level conversion,
+      phrase-level conversion, variant conversion and regional idioms among Mainland China,
+      Taiwan and Hong kong.
+    '';
+    maintainers = with maintainers; [ sifmelcara ];
+    platforms = with platforms; linux ++ darwin;
+  };
+}
diff --git a/pkgs/tools/text/papertrail/Gemfile b/pkgs/tools/text/papertrail/Gemfile
new file mode 100755
index 00000000000..199cd1422aa
--- /dev/null
+++ b/pkgs/tools/text/papertrail/Gemfile
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+source "https://rubygems.org"
+
+gem "papertrail"
diff --git a/pkgs/tools/text/papertrail/Gemfile.lock b/pkgs/tools/text/papertrail/Gemfile.lock
new file mode 100644
index 00000000000..37cd23eab6f
--- /dev/null
+++ b/pkgs/tools/text/papertrail/Gemfile.lock
@@ -0,0 +1,17 @@
+GEM
+  remote: https://rubygems.org/
+  specs:
+    ansi (1.5.0)
+    chronic (0.10.2)
+    papertrail (0.10.1)
+      ansi (~> 1.5)
+      chronic (~> 0.10)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  papertrail
+
+BUNDLED WITH
+   2.1.4
diff --git a/pkgs/tools/text/papertrail/default.nix b/pkgs/tools/text/papertrail/default.nix
new file mode 100644
index 00000000000..afc9d2d89e7
--- /dev/null
+++ b/pkgs/tools/text/papertrail/default.nix
@@ -0,0 +1,31 @@
+{ lib, stdenv, bundlerEnv, ruby, bundlerUpdateScript }:
+
+let
+  papertrail-env = bundlerEnv {
+    name = "papertrail-env";
+    inherit ruby;
+    gemfile = ./Gemfile;
+    lockfile = ./Gemfile.lock;
+    gemset = ./gemset.nix;
+  };
+in stdenv.mkDerivation {
+  pname = "papertrail";
+  version = (import ./gemset.nix).papertrail.version;
+
+  dontUnpack = true;
+
+  installPhase = ''
+    mkdir -p $out/bin
+    ln -s ${papertrail-env}/bin/papertrail $out/bin/papertrail
+  '';
+
+  passthru.updateScript = bundlerUpdateScript "papertrail";
+
+  meta = with lib; {
+    description = "Command-line client for Papertrail log management service";
+    homepage    = "https://github.com/papertrail/papertrail-cli/";
+    license     = licenses.mit;
+    maintainers = with maintainers; [ nicknovitski ];
+    platforms   = ruby.meta.platforms;
+  };
+}
diff --git a/pkgs/tools/text/papertrail/gemset.nix b/pkgs/tools/text/papertrail/gemset.nix
new file mode 100644
index 00000000000..dcdfcdf7ea5
--- /dev/null
+++ b/pkgs/tools/text/papertrail/gemset.nix
@@ -0,0 +1,26 @@
+{
+  ansi = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "14ims9zfal4gs2wpx2m5rd8zsrl2k794d359shkrsgg3fhr2a22l";
+      type = "gem";
+    };
+    version = "1.5.0";
+  };
+  chronic = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1hrdkn4g8x7dlzxwb1rfgr8kw3bp4ywg5l4y4i9c2g5cwv62yvvn";
+      type = "gem";
+    };
+    version = "0.10.2";
+  };
+  papertrail = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0vb7bh7qh5hr4v3w711bl0yrr3rlhz5c3h3qx3fq31dr5y4100v7";
+      type = "gem";
+    };
+    version = "0.10.1";
+  };
+}
diff --git a/pkgs/tools/text/par/default.nix b/pkgs/tools/text/par/default.nix
new file mode 100644
index 00000000000..e4c6c5d0c08
--- /dev/null
+++ b/pkgs/tools/text/par/default.nix
@@ -0,0 +1,42 @@
+{lib, stdenv, fetchurl, fetchpatch}:
+
+stdenv.mkDerivation {
+  pname = "par";
+  version = "1.52";
+
+  src = fetchurl {
+    url = "http://www.nicemice.net/par/Par152.tar.gz";
+    sha256 = "33dcdae905f4b4267b4dc1f3efb032d79705ca8d2122e17efdecfd8162067082";
+  };
+
+  patches = [
+    # A patch by Jérôme Pouiller that adds support for multibyte
+    # charsets (like UTF-8), plus Debian packaging.
+    (fetchpatch {
+      url = "http://sysmic.org/dl/par/par-1.52-i18n.4.patch";
+      sha256 = "0alw44lf511jmr38jnh4j0mpp7vclgy0grkxzqf7q158vzdb6g23";
+    })
+  ];
+
+  makefile = "protoMakefile";
+  preBuild = ''
+    makeFlagsArray+=(CC="${stdenv.cc.targetPrefix}cc -c" LINK1=${stdenv.cc.targetPrefix}cc)
+  '';
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp par $out/bin
+
+    mkdir -p $out/share/man/man1
+    cp  par.1 $out/share/man/man1
+  '';
+
+
+  meta = with lib; {
+    homepage = "http://www.nicemice.net/par/";
+    description = "Paragraph reflow for email";
+    platforms = platforms.unix;
+    # See https://fedoraproject.org/wiki/Licensing/Par for license details
+    license = licenses.free;
+  };
+}
diff --git a/pkgs/tools/text/patchutils/0.3.3.nix b/pkgs/tools/text/patchutils/0.3.3.nix
new file mode 100644
index 00000000000..f50354199c3
--- /dev/null
+++ b/pkgs/tools/text/patchutils/0.3.3.nix
@@ -0,0 +1,7 @@
+{ callPackage, ... } @ args:
+
+callPackage ./generic.nix (args // {
+  version = "0.3.3";
+  sha256 = "0g5df00cj4nczrmr4k791l7la0sq2wnf8rn981fsrz1f3d2yix4i";
+  patches = [ ./drop-comments.patch ]; # we would get into a cycle when using fetchpatch on this one
+})
diff --git a/pkgs/tools/text/patchutils/0.4.2.nix b/pkgs/tools/text/patchutils/0.4.2.nix
new file mode 100644
index 00000000000..1b2c0d6b1f3
--- /dev/null
+++ b/pkgs/tools/text/patchutils/0.4.2.nix
@@ -0,0 +1,8 @@
+{ callPackage, python3, ... } @ args:
+
+callPackage ./generic.nix (args // {
+  version = "0.4.2";
+  sha256 = "sha256-iHWwll/jPeYriQ9s15O+f6/kGk5VLtv2QfH+1eu/Re0=";
+  # for gitdiff
+  extraBuildInputs = [ python3 ];
+})
diff --git a/pkgs/tools/text/patchutils/default.nix b/pkgs/tools/text/patchutils/default.nix
new file mode 100644
index 00000000000..902773f40fa
--- /dev/null
+++ b/pkgs/tools/text/patchutils/default.nix
@@ -0,0 +1,6 @@
+{ callPackage, ... } @ args:
+
+callPackage ./generic.nix (args // {
+  version = "0.3.4";
+  sha256 = "0xp8mcfyi5nmb5a2zi5ibmyshxkb1zv1dgmnyn413m7ahgdx8mfg";
+})
diff --git a/pkgs/tools/text/patchutils/drop-comments.patch b/pkgs/tools/text/patchutils/drop-comments.patch
new file mode 100644
index 00000000000..e02693a5683
--- /dev/null
+++ b/pkgs/tools/text/patchutils/drop-comments.patch
@@ -0,0 +1,84 @@
+From 58987954647f51dc42fb13b7759923c6170dd905 Mon Sep 17 00:00:00 2001
+From: Tim Waugh <twaugh@redhat.com>
+Date: Fri, 9 May 2014 16:23:27 +0100
+Subject: Make --clean drop comments after '@@' lines as well (trac #29).
+
+
+diff --git a/Makefile.am b/Makefile.am
+index 99ad2a3..f3c6dbc 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -198,6 +198,7 @@ TESTS = tests/newline1/run-test \
+ 	tests/convert1/run-test \
+ 	tests/convert2/run-test \
+ 	tests/clean1/run-test \
++	tests/clean2/run-test \
+ 	tests/stdin/run-test
+ 
+ # These ones don't work yet.
+diff --git a/src/filterdiff.c b/src/filterdiff.c
+index 383e72b..6ca2316 100644
+--- a/src/filterdiff.c
++++ b/src/filterdiff.c
+@@ -2,7 +2,7 @@
+  * filterdiff - extract (or exclude) a diff from a diff file
+  * lsdiff - show which files are modified by a patch
+  * grepdiff - show files modified by a patch containing a regexp
+- * Copyright (C) 2001, 2002, 2003, 2004, 2008, 2009, 2011 Tim Waugh <twaugh@redhat.com>
++ * Copyright (C) 2001, 2002, 2003, 2004, 2008, 2009, 2011, 2013, 2014 Tim Waugh <twaugh@redhat.com>
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -408,7 +408,8 @@ do_unified (FILE *f, char *header[2], int match, char **line,
+ 							 " Hunk #%lu, %s",
+ 							 hunknum, bestname);
+ 
+-					fputs (trailing, output_to);
++					fputs (clean_comments ? "\n" : trailing,
++					       output_to);
+ 					break;
+ 				case Before:
+ 					// Note the initial line number
+diff --git a/tests/clean2/run-test b/tests/clean2/run-test
+new file mode 100755
+index 0000000..42320df
+--- /dev/null
++++ b/tests/clean2/run-test
+@@ -0,0 +1,34 @@
++#!/bin/sh
++
++# This is a filterdiff(1) testcase.
++# Test: Make sure --clean removes hunk-level comments.
++
++
++. ${top_srcdir-.}/tests/common.sh
++
++cat << EOF > diff
++non-diff line
++--- a/file1
+++++ b/file1
++@@ -0,0 +1 @@ this is a hunk-level comment
+++a
++EOF
++
++${FILTERDIFF} --clean diff 2>errors >filtered || exit 1
++[ -s errors ] && exit 1
++
++cat << EOF | cmp - filtered || exit 1
++--- a/file1
+++++ b/file1
++@@ -0,0 +1 @@
+++a
++EOF
++
++${FILTERDIFF} --clean -x file1 diff 2>errors >filtered || exit 1
++[ -s errors ] && exit 1
++cat << EOF | cmp - filtered || exit 1
++--- a/file1
+++++ b/file1
++@@ -0,0 +1 @@
+++a
++EOF
+-- 
+cgit v0.10.1
+
diff --git a/pkgs/tools/text/patchutils/generic.nix b/pkgs/tools/text/patchutils/generic.nix
new file mode 100644
index 00000000000..d1cd4334e11
--- /dev/null
+++ b/pkgs/tools/text/patchutils/generic.nix
@@ -0,0 +1,45 @@
+{ lib, stdenv, fetchurl, perl, makeWrapper
+, version, sha256, patches ? [], extraBuildInputs ? []
+, ...
+}:
+stdenv.mkDerivation rec {
+  pname = "patchutils";
+  inherit version patches;
+
+  src = fetchurl {
+    url = "http://cyberelk.net/tim/data/patchutils/stable/${pname}-${version}.tar.xz";
+    inherit sha256;
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+  buildInputs = [ perl ] ++ extraBuildInputs;
+  hardeningDisable = [ "format" ];
+
+  # tests fail when building in parallel
+  enableParallelBuilding = false;
+
+  postInstall = ''
+    for bin in $out/bin/{splitdiff,rediff,editdiff,dehtmldiff}; do
+      wrapProgram "$bin" \
+        --prefix PATH : "$out/bin"
+    done
+  '';
+
+  doCheck = lib.versionAtLeast version "0.3.4";
+
+  preCheck = ''
+    patchShebangs tests
+    chmod +x scripts/*
+  '' + lib.optionalString (lib.versionOlder version "0.4.2") ''
+    find tests -type f -name 'run-test' \
+      -exec sed -i '{}' -e 's|/bin/echo|echo|g' \;
+  '';
+
+  meta = with lib; {
+    description = "Tools to manipulate patch files";
+    homepage = "http://cyberelk.net/tim/software/patchutils";
+    license = licenses.gpl2Plus;
+    platforms = platforms.all;
+    maintainers = with maintainers; [ artturin ];
+  };
+}
diff --git a/pkgs/tools/text/pbgopy/default.nix b/pkgs/tools/text/pbgopy/default.nix
new file mode 100644
index 00000000000..d4ed4eb0f03
--- /dev/null
+++ b/pkgs/tools/text/pbgopy/default.nix
@@ -0,0 +1,22 @@
+{ lib, buildGoModule, fetchFromGitHub }:
+
+buildGoModule rec {
+  pname = "pbgopy";
+  version = "0.3.0";
+
+  src = fetchFromGitHub {
+    owner = "nakabonne";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-P/MFDFMsqSTVErTM9izJJSMIbiOcbQ9Ya10/w6NRcYw=";
+  };
+
+  vendorSha256 = "sha256-S2X74My6wyDZOsEYTDilCFaYgV2vQzU0jOAY9cEkJ6A=";
+
+  meta = with lib; {
+    description = "Copy and paste between devices";
+    homepage = "https://github.com/nakabonne/pbgopy";
+    license = licenses.mit;
+    maintainers = [ maintainers.ivar ];
+  };
+}
diff --git a/pkgs/tools/text/peco/default.nix b/pkgs/tools/text/peco/default.nix
new file mode 100644
index 00000000000..36951be7edb
--- /dev/null
+++ b/pkgs/tools/text/peco/default.nix
@@ -0,0 +1,25 @@
+{ lib, buildGoModule, fetchFromGitHub }:
+
+buildGoModule rec {
+  pname = "peco";
+  version = "0.5.10";
+
+  subPackages = [ "cmd/peco" ];
+
+  src = fetchFromGitHub {
+    owner = "peco";
+    repo = "peco";
+    rev = "v${version}";
+    sha256 = "sha256-Iu2MclUbUYX1FuMnE65Qdk0S+5+K3HW86WIdQrNUyY8=";
+  };
+
+  vendorSha256 = "sha256-+HQz7UUgATdgSWlI1dg2DdQRUSke9MyAtXgLikFhF90=";
+
+  meta = with lib; {
+    description = "Simplistic interactive filtering tool";
+    homepage = "https://github.com/peco/peco";
+    changelog = "https://github.com/peco/peco/blob/v${version}/Changes";
+    license = licenses.mit;
+    maintainers = with maintainers; [ pSub ];
+  };
+}
diff --git a/pkgs/tools/text/pinyin-tool/default.nix b/pkgs/tools/text/pinyin-tool/default.nix
new file mode 100644
index 00000000000..9d98385933b
--- /dev/null
+++ b/pkgs/tools/text/pinyin-tool/default.nix
@@ -0,0 +1,24 @@
+{ stdenv, lib, rustPlatform, fetchFromGitHub, Security }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "pinyin-tool";
+  version = "0.1.3";
+
+  src = fetchFromGitHub {
+    owner = "briankung";
+    repo = pname;
+    rev = version;
+    sha256 = "1gwqwxlvdrm4sdyqkvpvvfi6jh6qqn6qybn0z66wm06k62f8zj5b";
+  };
+
+  cargoSha256 = "1ixl4bsb8c8dmz9s28a2v5l5f2hi3g9xjy6ribmhybpwmfs4mr4d";
+
+  buildInputs = lib.optionals stdenv.isDarwin [ Security ];
+
+  meta = with lib; {
+    description = "A simple command line tool for converting Chinese characters to space-separate pinyin words";
+    homepage = "https://github.com/briankung/pinyin-tool";
+    license = licenses.mit;
+    maintainers = with maintainers; [ neonfuz ];
+  };
+}
diff --git a/pkgs/tools/text/platinum-searcher/default.nix b/pkgs/tools/text/platinum-searcher/default.nix
new file mode 100644
index 00000000000..ca89b7dc2d8
--- /dev/null
+++ b/pkgs/tools/text/platinum-searcher/default.nix
@@ -0,0 +1,24 @@
+{ lib, buildGoPackage, fetchFromGitHub }:
+
+buildGoPackage rec {
+  pname = "the_platinum_searcher";
+  version = "2.1.5";
+  rev = "v${version}";
+
+  goPackagePath = "github.com/monochromegane/the_platinum_searcher";
+
+  src = fetchFromGitHub {
+    inherit rev;
+    owner = "monochromegane";
+    repo = "the_platinum_searcher";
+    sha256 = "1y7kl3954dimx9hp2bf1vjg1h52hj1v6cm4f5nhrqzwrawp0b6q0";
+  };
+
+  goDeps = ./deps.nix;
+
+  meta = with lib; {
+    homepage = "https://github.com/monochromegane/the_platinum_searcher";
+    description = "A code search tool similar to ack and the_silver_searcher(ag)";
+    license = licenses.mit;
+  };
+}
diff --git a/pkgs/tools/text/platinum-searcher/deps.nix b/pkgs/tools/text/platinum-searcher/deps.nix
new file mode 100644
index 00000000000..04fb9bd4be3
--- /dev/null
+++ b/pkgs/tools/text/platinum-searcher/deps.nix
@@ -0,0 +1,83 @@
+[
+  {
+    goPackagePath = "gopkg.in/yaml.v2";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/yaml.v2";
+      rev = "a5b47d31c556af34a302ce5d659e6fea44d90de0";
+      sha256 = "0v6l48fshdjrqzyq1kwn22gy7vy434xdr1i0lm3prsf6jbln9fam";
+    };
+  }
+  {
+    goPackagePath = "github.com/jessevdk/go-flags";
+    fetch = {
+      type = "git";
+      url = "https://github.com/jessevdk/go-flags";
+      rev = "4e64e4a4e2552194cf594243e23aa9baf3b4297e";
+      sha256 = "02x7f1wm8119s27h4dc3a4aw6shydnpnnkvzwg5xm0snn5kb4zxm";
+    };
+  }
+  {
+    goPackagePath = "github.com/BurntSushi/toml";
+    fetch = {
+      type = "git";
+      url = "https://github.com/BurntSushi/toml";
+      rev = "99064174e013895bbd9b025c31100bd1d9b590ca";
+      sha256 = "058qrar8rvw3wb0ci1mf1axnqq2729cvv9zmdr4ms2nn9s97yiz9";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/text";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/text";
+      rev = "a49bea13b776691cb1b49873e5d8df96ec74831a";
+      sha256 = "1pcmgf88wml6ca8v63nh3nxsfvpzjv3c4qj2w2wkizbil826g7as";
+    };
+  }
+  {
+    goPackagePath = "github.com/monochromegane/conflag";
+    fetch = {
+      type = "git";
+      url = "https://github.com/monochromegane/conflag";
+      rev = "6d68c9aa4183844ddc1655481798fe4d90d483e9";
+      sha256 = "0csfr5c8d3kbna9sqhzfp2z06wq6mc6ijja1zj2i82kzsq8534wa";
+    };
+  }
+  {
+    goPackagePath = "github.com/monochromegane/go-home";
+    fetch = {
+      type = "git";
+      url = "https://github.com/monochromegane/go-home";
+      rev = "25d9dda593924a11ea52e4ffbc8abdb0dbe96401";
+      sha256 = "172chakrj22xfm0bcda4qj5zqf7lwr53pzwc3xj6wz8vd2bcxkww";
+    };
+  }
+  {
+    goPackagePath = "github.com/monochromegane/terminal";
+    fetch = {
+      type = "git";
+      url = "https://github.com/monochromegane/terminal";
+      rev = "2da212063ce19aed90ee5bbb00ad1ad7393d7f48";
+      sha256 = "1rddaq9pk5q57ildms35iihghqk505gb349pb0f6k3svchay38nh";
+    };
+  }
+  {
+    goPackagePath = "github.com/monochromegane/go-gitignore";
+    fetch = {
+      type = "git";
+      url = "https://github.com/monochromegane/go-gitignore";
+      rev = "38717d0a108ca0e5af632cd6845ca77d45b50729";
+      sha256 = "0r1inabpgg6sn6i47b02hcmd2p4dc1ab1mcy20mn1b2k3mpdj4b7";
+    };
+  }
+  {
+    goPackagePath = "github.com/shiena/ansicolor";
+    fetch = {
+      type = "git";
+      url = "https://github.com/shiena/ansicolor";
+      rev = "a422bbe96644373c5753384a59d678f7d261ff10";
+      sha256 = "1dcn8a9z6a5dxa2m3fkppnajcls8lanbl38qggkf646yi5qsk1hc";
+    };
+  }
+]
diff --git a/pkgs/tools/text/pn/default.nix b/pkgs/tools/text/pn/default.nix
new file mode 100644
index 00000000000..d77b36651d6
--- /dev/null
+++ b/pkgs/tools/text/pn/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, cmake, libphonenumber, icu, protobuf }:
+
+stdenv.mkDerivation rec {
+  pname = "pn";
+  version = "0.9.0";
+
+  src = fetchFromGitHub {
+    owner = "Orange-OpenSource";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-vRF9MPcw/hCreHVLD6QB7g1r0wQiZv1xrfzIHj1Yf9M=";
+  };
+
+  nativeBuildInputs = [ cmake ];
+  buildInputs = [ libphonenumber icu protobuf ];
+
+  meta = with lib; {
+    description = "A libphonenumber command-line wrapper";
+    homepage = "https://github.com/Orange-OpenSource/pn";
+    license = licenses.asl20;
+    platforms = platforms.unix;
+    maintainers = [ maintainers.McSinyx ];
+  };
+}
diff --git a/pkgs/tools/text/podiff/default.nix b/pkgs/tools/text/podiff/default.nix
new file mode 100644
index 00000000000..2078c75f136
--- /dev/null
+++ b/pkgs/tools/text/podiff/default.nix
@@ -0,0 +1,25 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation {
+  pname = "podiff";
+  version = "1.3";
+
+  src = fetchurl {
+    url = "ftp://download.gnu.org.ua/pub/release/podiff/podiff-1.3.tar.gz";
+    sha256 = "sha256-7fpix+GkXsfpRgnkHtk1iXF6ILHri7BtUhNPK6sDQFA=";
+  };
+
+  patchPhase = ''
+    sed "s#PREFIX=/usr#PREFIX=$out#g" -i Makefile
+    mkdir -p $out/bin
+    mkdir -p $out/share/man/man1
+  '';
+
+  meta = with lib; {
+    description = "Finds differences in translations between two PO files, or revisions";
+    homepage = "http://puszcza.gnu.org.ua/software/podiff";
+    license = licenses.gpl3Plus;
+    maintainers = [ maintainers.goibhniu ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/poedit/default.nix b/pkgs/tools/text/poedit/default.nix
new file mode 100644
index 00000000000..fcb2a7019ac
--- /dev/null
+++ b/pkgs/tools/text/poedit/default.nix
@@ -0,0 +1,49 @@
+{ lib, stdenv, fetchFromGitHub, autoconf, automake, libtool, gettext, pkg-config, wxGTK31-gtk3,
+  boost, icu, lucenepp, asciidoc, libxslt, xmlto, gtk3, gtkspell3, pugixml,
+  nlohmann_json, hicolor-icon-theme, wrapGAppsHook }:
+
+stdenv.mkDerivation rec {
+  pname = "poedit";
+  version = "3.0.1";
+
+  src = fetchFromGitHub {
+    owner = "vslavik";
+    repo = "poedit";
+    rev = "v${version}-oss";
+    sha256 = "sha256-PBAOCAO3OrBE7lOho7nJNEpqwds7XiblN/f+GonrXHA=";
+  };
+
+  nativeBuildInputs = [ autoconf automake asciidoc wrapGAppsHook
+    libxslt xmlto boost libtool pkg-config ];
+
+  buildInputs = [ lucenepp nlohmann_json wxGTK31-gtk3 icu pugixml gtk3 gtkspell3 hicolor-icon-theme ];
+
+  propagatedBuildInputs = [ gettext ];
+
+  preConfigure = "
+    patchShebangs bootstrap
+    ./bootstrap
+  ";
+
+  configureFlags = [
+    "--without-cld2"
+    "--without-cpprest"
+    "--with-boost-libdir=${boost.out}/lib"
+    "CPPFLAGS=-I${nlohmann_json}/include/nlohmann/"
+    "LDFLAGS=-llucene++"
+  ];
+
+  preFixup = ''
+    gappsWrapperArgs+=(--prefix PATH : "${lib.makeBinPath [ gettext ]}")
+  '';
+
+  enableParallelBuilding = true;
+
+  meta = with lib; {
+    description = "Cross-platform gettext catalogs (.po files) editor";
+    homepage = "https://www.poedit.net/";
+    license = licenses.mit;
+    platforms = platforms.unix;
+    maintainers = with maintainers; [ dasj19 ];
+  };
+}
diff --git a/pkgs/tools/text/popfile/default.nix b/pkgs/tools/text/popfile/default.nix
new file mode 100644
index 00000000000..7dec478a634
--- /dev/null
+++ b/pkgs/tools/text/popfile/default.nix
@@ -0,0 +1,60 @@
+{ lib, stdenv, fetchzip, makeWrapper, perlPackages,
+... }:
+
+stdenv.mkDerivation rec {
+  appname = "popfile";
+  version = "1.1.3";
+  name = "${appname}-${version}";
+
+  src = fetchzip {
+    url = "https://getpopfile.org/downloads/${appname}-${version}.zip";
+    sha256 = "0gcib9j7zxk8r2vb5dbdz836djnyfza36vi8215nxcdfx1xc7l63";
+    stripRoot = false;
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+  buildInputs = (with perlPackages; [
+    ## These are all taken from the popfile documentation as applicable to Linux
+    ## https://getpopfile.org/docs/howtos:allplatformsrequireperl
+    perl
+    DBI
+    DBDSQLite
+    HTMLTagset
+    TimeDate # == DateParse
+    HTMLTemplate
+    # IO::Socket::Socks is not in nixpkgs
+    # IOSocketSocks
+    IOSocketSSL
+    NetSSLeay
+    SOAPLite
+  ]);
+
+  installPhase = ''
+    mkdir -p $out/bin
+    # I user `cd` rather than `cp $out/* ...` b/c the * breaks syntax
+    # highlighting in emacs for me.
+    cd $src
+    cp -r * $out/bin
+    cd $out/bin
+    chmod +x *.pl
+
+    find $out -name '*.pl' -executable | while read path; do
+      wrapProgram "$path" \
+        --prefix PERL5LIB : $PERL5LIB:$out/bin \
+        --set POPFILE_ROOT $out/bin \
+        --run 'export POPFILE_USER=''${POPFILE_USER:-$HOME/.popfile}' \
+        --run 'test -d "$POPFILE_USER" || mkdir -m 0700 -p "$POPFILE_USER"'
+    done
+  '';
+
+  meta = {
+    description = "An email classification system that automatically sorts messages and fights spam";
+    homepage = "https://getpopfile.org/";
+    license = lib.licenses.gpl2;
+
+    # Should work on macOS, but havent tested it.
+    # Windows support is more complicated.
+    # https://getpopfile.org/docs/faq:systemrequirements
+    platforms = lib.platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/proselint/default.nix b/pkgs/tools/text/proselint/default.nix
new file mode 100644
index 00000000000..3f1b79c3e01
--- /dev/null
+++ b/pkgs/tools/text/proselint/default.nix
@@ -0,0 +1,22 @@
+{ lib, fetchurl, buildPythonApplication, click, future, six }:
+
+buildPythonApplication rec {
+  pname = "proselint";
+  version = "0.13.0";
+
+  doCheck = false; # fails to pass because it tries to run in home directory
+
+  src = fetchurl {
+    url = "mirror://pypi/p/proselint/${pname}-${version}.tar.gz";
+    sha256 = "7dd2b63cc2aa390877c4144fcd3c80706817e860b017f04882fbcd2ab0852a58";
+  };
+
+  propagatedBuildInputs = [ click future six ];
+
+  meta = with lib; {
+    description = "A linter for prose";
+    homepage = "http://proselint.com";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ alibabzo ];
+  };
+}
diff --git a/pkgs/tools/text/pru/Gemfile b/pkgs/tools/text/pru/Gemfile
new file mode 100644
index 00000000000..84e6742401e
--- /dev/null
+++ b/pkgs/tools/text/pru/Gemfile
@@ -0,0 +1,2 @@
+source 'https://rubygems.org'
+gem 'pru'
diff --git a/pkgs/tools/text/pru/Gemfile.lock b/pkgs/tools/text/pru/Gemfile.lock
new file mode 100644
index 00000000000..98a00ad5368
--- /dev/null
+++ b/pkgs/tools/text/pru/Gemfile.lock
@@ -0,0 +1,13 @@
+GEM
+  remote: https://rubygems.org/
+  specs:
+    pru (0.2.1)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  pru
+
+BUNDLED WITH
+   2.1.4
diff --git a/pkgs/tools/text/pru/default.nix b/pkgs/tools/text/pru/default.nix
new file mode 100644
index 00000000000..26e74344248
--- /dev/null
+++ b/pkgs/tools/text/pru/default.nix
@@ -0,0 +1,24 @@
+{ lib
+, bundlerApp
+, bundlerUpdateScript
+}:
+
+bundlerApp rec {
+  pname = "pru";
+  gemdir = ./.;
+  exes = [ "pru" ];
+
+  meta = with lib; {
+    homepage = "https://github.com/grosser/pru";
+    description = "Pipeable Ruby";
+    longDescription = ''
+      pru allows to use Ruby scripts as filters, working as a convenient,
+      higher-level replacement of typical text processing tools (like sed, awk,
+      grep etc.).
+    '';
+    license = licenses.mit;
+    maintainers = with maintainers; [ AndersonTorres ];
+  };
+
+  passthru.updateScript = bundlerUpdateScript pname;
+}
diff --git a/pkgs/tools/text/pru/gemset.nix b/pkgs/tools/text/pru/gemset.nix
new file mode 100644
index 00000000000..76d469ef1b7
--- /dev/null
+++ b/pkgs/tools/text/pru/gemset.nix
@@ -0,0 +1,12 @@
+{
+  pru = {
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1imavf7wlbdfxvkrf838pp3cyfib0r7nzv0chnhyxagy1kk969r2";
+      type = "gem";
+    };
+    version = "0.2.1";
+  };
+}
diff --git a/pkgs/tools/text/qgrep/default.nix b/pkgs/tools/text/qgrep/default.nix
new file mode 100644
index 00000000000..032e9474128
--- /dev/null
+++ b/pkgs/tools/text/qgrep/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, fetchFromGitHub, CoreServices, CoreFoundation, fetchpatch }:
+
+stdenv.mkDerivation rec {
+  version = "1.1";
+  pname = "qgrep";
+
+  src = fetchFromGitHub {
+    owner = "zeux";
+    repo = "qgrep";
+    rev = "v${version}";
+    sha256 = "046ccw34vz2k5jn6gyxign5gs2qi7i50jy9b74wqv7sjf5zayrh0";
+    fetchSubmodules = true;
+  };
+
+  patches = lib.optionals stdenv.isDarwin [
+    (fetchpatch {
+      url = "https://github.com/zeux/qgrep/commit/21c4d1a5ab0f0bdaa0b5ca993c1315c041418cc6.patch";
+      sha256 = "0wpxzrd9pmhgbgby17vb8279xwvkxfdd99gvv7r74indgdxqg7v8";
+    })
+  ];
+
+  buildInputs = lib.optionals stdenv.isDarwin [ CoreServices CoreFoundation ];
+
+  postPatch = lib.optionalString stdenv.isAarch64 ''
+    substituteInPlace Makefile \
+      --replace "-msse2" "" --replace "-DUSE_SSE2" ""
+  '';
+
+  installPhase = ''
+    install -Dm755 qgrep $out/bin/qgrep
+  '';
+
+  meta = with lib; {
+    description = "Fast regular expression grep for source code with incremental index updates";
+    homepage = "https://github.com/zeux/qgrep";
+    license = licenses.mit;
+    maintainers = [ maintainers.yrashk ];
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/qprint/default.nix b/pkgs/tools/text/qprint/default.nix
new file mode 100644
index 00000000000..56f5b5becbd
--- /dev/null
+++ b/pkgs/tools/text/qprint/default.nix
@@ -0,0 +1,29 @@
+{ fetchurl, lib, stdenv }:
+
+stdenv.mkDerivation rec {
+  pname = "qprint";
+  version = "1.1";
+
+  src = fetchurl {
+    url = "https://www.fourmilab.ch/webtools/qprint/qprint-${version}.tar.gz";
+    sha256 = "1701cnb1nl84rmcpxzq11w4cyj4385jh3gx4aqxznwf8a4fwmagz";
+  };
+
+  doCheck = true;
+
+  checkTarget = "wringer";
+
+  preInstall = ''
+    mkdir -p $out/bin
+    mkdir -p $out/share/man/man1
+  '';
+
+  meta = {
+    homepage = "https://www.fourmilab.ch/webtools/qprint/";
+    license = lib.licenses.publicDomain;
+    description = "Encode and decode Quoted-Printable files";
+    maintainers = [ lib.maintainers.tv ];
+    platforms = lib.platforms.all;
+  };
+
+}
diff --git a/pkgs/tools/text/qshowdiff/default.nix b/pkgs/tools/text/qshowdiff/default.nix
new file mode 100644
index 00000000000..8396e39e6d1
--- /dev/null
+++ b/pkgs/tools/text/qshowdiff/default.nix
@@ -0,0 +1,27 @@
+{ lib, stdenv, fetchFromGitHub, qt4, perl, pkg-config }:
+
+stdenv.mkDerivation rec {
+  pname = "qshowdiff";
+  version = "1.2";
+
+  src = fetchFromGitHub {
+    owner = "danfis";
+    repo = "qshowdiff";
+    rev = "v${version}";
+    sha256 = "g3AWQ6/LSF59ztzdgNuLi+8d6fFTPiC9z0yXMdPdB5U=";
+  };
+
+  nativeBuildInputs = [ pkg-config ];
+  buildInputs = [ qt4 perl ];
+
+  configurePhase = ''
+    mkdir -p $out/{bin,man/man1}
+    makeFlags="PREFIX=$out CC=$CXX"
+  '';
+
+  meta = {
+    homepage = "http://qshowdiff.danfis.cz/";
+    description = "Colourful diff viewer";
+    license = lib.licenses.gpl3Plus;
+  };
+}
diff --git a/pkgs/tools/text/reckon/Gemfile b/pkgs/tools/text/reckon/Gemfile
new file mode 100644
index 00000000000..f708ddd9366
--- /dev/null
+++ b/pkgs/tools/text/reckon/Gemfile
@@ -0,0 +1,2 @@
+source 'https://rubygems.org'
+gem 'reckon'
diff --git a/pkgs/tools/text/reckon/Gemfile.lock b/pkgs/tools/text/reckon/Gemfile.lock
new file mode 100644
index 00000000000..18dc624c3da
--- /dev/null
+++ b/pkgs/tools/text/reckon/Gemfile.lock
@@ -0,0 +1,19 @@
+GEM
+  remote: https://rubygems.org/
+  specs:
+    chronic (0.10.2)
+    highline (2.0.3)
+    rchardet (1.8.0)
+    reckon (0.8.0)
+      chronic (>= 0.3.0)
+      highline (>= 1.5.2)
+      rchardet (>= 1.8.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  reckon
+
+BUNDLED WITH
+   2.2.20
diff --git a/pkgs/tools/text/reckon/default.nix b/pkgs/tools/text/reckon/default.nix
new file mode 100644
index 00000000000..91233dfe97b
--- /dev/null
+++ b/pkgs/tools/text/reckon/default.nix
@@ -0,0 +1,33 @@
+{ stdenv, lib, bundlerEnv, bundlerUpdateScript, makeWrapper }:
+
+stdenv.mkDerivation rec {
+  pname = "reckon";
+  version = (import ./gemset.nix).reckon.version;
+
+  dontUnpack = true;
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  installPhase = let
+    env = bundlerEnv {
+      name = "${pname}-${version}-gems";
+
+      gemdir = ./.;
+    };
+  in ''
+    runHook preInstall
+    mkdir -p $out/bin
+    makeWrapper ${env}/bin/reckon $out/bin/reckon
+    runHook postInstall
+  '';
+
+  passthru.updateScript = bundlerUpdateScript "reckon";
+
+  meta = with lib; {
+    description = "Flexibly import bank account CSV files into Ledger for command line accounting";
+    license = licenses.mit;
+    maintainers = with maintainers; [ nicknovitski ];
+    platforms = platforms.unix;
+    changelog = "https://github.com/cantino/reckon/blob/v${version}/CHANGELOG.md";
+  };
+}
diff --git a/pkgs/tools/text/reckon/gemset.nix b/pkgs/tools/text/reckon/gemset.nix
new file mode 100644
index 00000000000..0e2cc48886a
--- /dev/null
+++ b/pkgs/tools/text/reckon/gemset.nix
@@ -0,0 +1,43 @@
+{
+  chronic = {
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1hrdkn4g8x7dlzxwb1rfgr8kw3bp4ywg5l4y4i9c2g5cwv62yvvn";
+      type = "gem";
+    };
+    version = "0.10.2";
+  };
+  highline = {
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0yclf57n2j3cw8144ania99h1zinf8q3f5zrhqa754j6gl95rp9d";
+      type = "gem";
+    };
+    version = "2.0.3";
+  };
+  rchardet = {
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1isj1b3ywgg2m1vdlnr41lpvpm3dbyarf1lla4dfibfmad9csfk9";
+      type = "gem";
+    };
+    version = "1.8.0";
+  };
+  reckon = {
+    dependencies = ["chronic" "highline" "rchardet"];
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0qnghypb9pj7888096xwyrx7myhzk85x69ympxkxki3kxcgcrdfn";
+      type = "gem";
+    };
+    version = "0.8.0";
+  };
+}
diff --git a/pkgs/tools/text/recode/default.nix b/pkgs/tools/text/recode/default.nix
new file mode 100644
index 00000000000..8c49fb5ee7f
--- /dev/null
+++ b/pkgs/tools/text/recode/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchurl, python3, perl, intltool, flex, texinfo, libiconv, libintl }:
+
+stdenv.mkDerivation rec {
+  pname = "recode";
+  version = "3.7.12";
+
+  # Use official tarball, avoid need to bootstrap/generate build system
+  src = fetchurl {
+    url = "https://github.com/rrthomas/${pname}/releases/download/v${version}/${pname}-${version}.tar.gz";
+    hash = "sha256-TbHJB28E26oVlyb1AAhH5eWoOuyOXGT4ygQ4P2zaEtU=";
+  };
+
+  nativeBuildInputs = [ python3 python3.pkgs.cython perl intltool flex texinfo libiconv ];
+  buildInputs = [ libintl ];
+
+  enableParallelBuilding = true;
+
+  doCheck = true;
+
+  meta = {
+    homepage = "https://github.com/rrthomas/recode";
+    description = "Converts files between various character sets and usages";
+    changelog = "https://github.com/rrthomas/recode/raw/v${version}/NEWS";
+    platforms = lib.platforms.unix;
+    license = with lib.licenses; [ lgpl3Plus gpl3Plus ];
+    maintainers = with lib.maintainers; [ jcumming ];
+  };
+}
diff --git a/pkgs/tools/text/replace/default.nix b/pkgs/tools/text/replace/default.nix
new file mode 100644
index 00000000000..058c2ba3daa
--- /dev/null
+++ b/pkgs/tools/text/replace/default.nix
@@ -0,0 +1,34 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "replace";
+  version = "2.24";
+
+  src = fetchurl {
+    url = "http://hpux.connect.org.uk/ftp/hpux/Users/replace-${version}/replace-${version}-src-11.31.tar.gz";
+    sha256 = "18hkwhaz25s6209n5mpx9hmkyznlzygqj488p2l7nvp9zrlxb9sf";
+  };
+
+  outputs = [ "out" "man" ];
+
+  makeFlags = [
+    "TREE=\$(out)"
+    "MANTREE=\$(TREE)/share/man"
+    "CC=${stdenv.cc.targetPrefix}cc"
+  ];
+
+  preBuild = ''
+    sed -e "s@/bin/mv@$(type -P mv)@" -i replace.h
+  '';
+
+  preInstall = "mkdir -p \$out/share/man";
+  postInstall = "mv \$out/bin/replace \$out/bin/replace-literal";
+
+  patches = [./malloc.patch];
+
+  meta = {
+    homepage = "https://replace.richardlloyd.org.uk/";
+    description = "A tool to replace verbatim strings";
+    platforms = lib.platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/replace/malloc.patch b/pkgs/tools/text/replace/malloc.patch
new file mode 100644
index 00000000000..1ee95c4bae1
--- /dev/null
+++ b/pkgs/tools/text/replace/malloc.patch
@@ -0,0 +1,13 @@
+diff -rc replace-2.24-orig/replace.h replace-2.24/replace.h
+*** replace-2.24-orig/replace.h	2004-10-07 15:15:06.000000000 +0200
+--- replace-2.24/replace.h	2008-02-21 14:57:47.000000000 +0100
+***************
+*** 11,17 ****
+  #include <ctype.h>
+  #include <unistd.h>
+  #include <string.h>
+- #include <malloc.h>
+  #include <sys/stat.h>
+  #include <ftw.h>
+  #include <utime.h>
+--- 11,16 ----
diff --git a/pkgs/tools/text/rgxg/default.nix b/pkgs/tools/text/rgxg/default.nix
new file mode 100644
index 00000000000..8e4d991e7bf
--- /dev/null
+++ b/pkgs/tools/text/rgxg/default.nix
@@ -0,0 +1,18 @@
+{ lib, stdenv, fetchzip }:
+
+stdenv.mkDerivation rec {
+  pname = "rgxg";
+  version = "0.1.2";
+
+  src = fetchzip {
+    url = "https://github.com/rgxg/rgxg/releases/download/v${version}/${pname}-${version}.tar.gz";
+    sha256 = "050jxc3qhfrm9fdbzd67hlsqlp4qk1fa20q1g2v919sh7s6v77si";
+  };
+
+  meta = with lib; {
+    description = "A C library and a command-line tool to generate (extended) regular expressions";
+    license = licenses.zlib;
+    maintainers = with maintainers; [ hloeffler ];
+    homepage = "https://rgxg.github.io/";
+  };
+}
diff --git a/pkgs/tools/text/ripgrep-all/default.nix b/pkgs/tools/text/ripgrep-all/default.nix
new file mode 100644
index 00000000000..0fc39b8da28
--- /dev/null
+++ b/pkgs/tools/text/ripgrep-all/default.nix
@@ -0,0 +1,63 @@
+{ stdenv, lib, fetchFromGitHub, rustPlatform, makeWrapper, ffmpeg
+, pandoc, poppler_utils, ripgrep, Security, imagemagick, tesseract
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "ripgrep-all";
+  version = "0.9.6";
+
+  src = fetchFromGitHub {
+    owner = "phiresky";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "1wjpgi7m3lxybllkr3r60zaphp02ykq2syq72q9ail2760cjcir6";
+  };
+
+  cargoSha256 = "1l71xj5crfb51wfp2bdvdqp1l8kg182n5d6w23lq2wjszaqcj7cw";
+  nativeBuildInputs = [ makeWrapper ];
+  buildInputs = lib.optional stdenv.isDarwin Security;
+
+  postInstall = ''
+    wrapProgram $out/bin/rga \
+      --prefix PATH ":" "${lib.makeBinPath [ ffmpeg pandoc poppler_utils ripgrep imagemagick tesseract ]}"
+  '';
+
+  # Use upstream's example data to run a couple of queries to ensure the dependencies
+  # for all of the adapters are available.
+  installCheckPhase = ''
+    set -e
+    export PATH="$PATH:$out/bin"
+
+    test1=$(rga --rga-no-cache "hello" exampledir/ | wc -l)
+    test2=$(rga --rga-no-cache --rga-adapters=tesseract "crate" exampledir/screenshot.png | wc -l)
+
+    if [ $test1 != 26 ]
+    then
+      echo "ERROR: test1 failed! Could not find the word 'hello' 26 times in the sample data."
+      exit 1
+    fi
+
+    if [ $test2 != 1 ]
+    then
+      echo "ERROR: test2 failed! Could not find the word 'crate' in the screenshot."
+      exit 1
+    fi
+  '';
+
+  doInstallCheck = true;
+
+  meta = with lib; {
+    description = "Ripgrep, but also search in PDFs, E-Books, Office documents, zip, tar.gz, and more";
+    longDescription = ''
+      Ripgrep, but also search in PDFs, E-Books, Office documents, zip, tar.gz, etc.
+
+      rga is a line-oriented search tool that allows you to look for a regex in
+      a multitude of file types. rga wraps the awesome ripgrep and enables it
+      to search in pdf, docx, sqlite, jpg, movie subtitles (mkv, mp4), etc.
+    '';
+    homepage = "https://github.com/phiresky/ripgrep-all";
+    license = with licenses; [ agpl3Plus ];
+    maintainers = with maintainers; [ zaninime ma27 ];
+    mainProgram = "rga";
+  };
+}
diff --git a/pkgs/tools/text/ripgrep/default.nix b/pkgs/tools/text/ripgrep/default.nix
new file mode 100644
index 00000000000..022f8bd25bb
--- /dev/null
+++ b/pkgs/tools/text/ripgrep/default.nix
@@ -0,0 +1,56 @@
+{ lib, stdenv
+, fetchFromGitHub
+, rustPlatform
+, asciidoctor
+, installShellFiles
+, pkg-config
+, Security
+, withPCRE2 ? true
+, pcre2
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "ripgrep";
+  version = "13.0.0";
+
+  src = fetchFromGitHub {
+    owner = "BurntSushi";
+    repo = pname;
+    rev = version;
+    sha256 = "0pdcjzfi0fclbzmmf701fdizb95iw427vy3m1svy6gdn2zwj3ldr";
+  };
+
+  cargoSha256 = "1kfdgh8dra4jxgcdb0lln5wwrimz0dpp33bq3h7jgs8ngaq2a9wp";
+
+  nativeBuildInputs = [ asciidoctor installShellFiles ]
+    ++ lib.optional withPCRE2 pkg-config;
+  buildInputs = lib.optional withPCRE2 pcre2
+    ++ lib.optional stdenv.isDarwin Security;
+
+  buildFeatures = lib.optional withPCRE2 "pcre2";
+
+  preFixup = ''
+    installManPage $releaseDir/build/ripgrep-*/out/rg.1
+
+    installShellCompletion $releaseDir/build/ripgrep-*/out/rg.{bash,fish}
+    installShellCompletion --zsh complete/_rg
+  '';
+
+  doInstallCheck = true;
+  installCheckPhase = ''
+    file="$(mktemp)"
+    echo "abc\nbcd\ncde" > "$file"
+    $out/bin/rg -N 'bcd' "$file"
+    $out/bin/rg -N 'cd' "$file"
+  '' + lib.optionalString withPCRE2 ''
+    echo '(a(aa)aa)' | $out/bin/rg -P '\((a*|(?R))*\)'
+  '';
+
+  meta = with lib; {
+    description = "A utility that combines the usability of The Silver Searcher with the raw speed of grep";
+    homepage = "https://github.com/BurntSushi/ripgrep";
+    license = with licenses; [ unlicense /* or */ mit ];
+    maintainers = with maintainers; [ tailhook globin ma27 zowoq ];
+    mainProgram = "rg";
+  };
+}
diff --git a/pkgs/tools/text/robodoc/default.nix b/pkgs/tools/text/robodoc/default.nix
new file mode 100644
index 00000000000..e30e8739797
--- /dev/null
+++ b/pkgs/tools/text/robodoc/default.nix
@@ -0,0 +1,48 @@
+{ lib
+, stdenv
+, fetchFromGitHub
+, autoreconfHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "robodoc";
+  version = "4.99.44";
+
+  src = fetchFromGitHub {
+    owner = "gumpu";
+    repo = "ROBODoc";
+    rev = "v${version}";
+    sha256 = "l3prSdaGhOvXmZfCPbsZJNocO7y20zJjLQpajRTJOqE=";
+  };
+
+  nativeBuildInputs = [ autoreconfHook ];
+
+  hardeningDisable = [ "format" ];
+
+  meta = with lib; {
+    homepage = "https://github.com/gumpu/ROBODoc";
+    description = "Documentation Extraction Tool";
+    longDescription = ''
+      ROBODoc is program documentation tool. The idea is to include for every
+      function or procedure a standard header containing all sorts of
+      information about the procedure or function. ROBODoc extracts these
+      headers from the source file and puts them in a separate
+      autodocs-file. ROBODoc thus allows you to include the program
+      documentation in the source code and avoid having to maintain two separate
+      documents. Or as Petteri puts it: "robodoc is very useful - especially for
+      programmers who don't like writing documents with Word or some other
+      strange tool."
+
+      ROBODoc can format the headers in a number of different formats: HTML,
+      RTF, LaTeX, or XML DocBook. In HTML mode it can generate cross links
+      between headers. You can even include parts of your source code.
+
+      ROBODoc works with many programming languages: For instance C, Pascal,
+      Shell Scripts, Assembler, COBOL, Occam, Postscript, Forth, Tcl/Tk, C++,
+      Java -- basically any program in which you can use remarks/comments.
+    '';
+    license = with licenses; gpl3Plus;
+    maintainers = with maintainers; [ AndersonTorres ];
+    platforms = with platforms; all;
+  };
+}
diff --git a/pkgs/tools/text/rosie/default.nix b/pkgs/tools/text/rosie/default.nix
new file mode 100644
index 00000000000..a4edf55f750
--- /dev/null
+++ b/pkgs/tools/text/rosie/default.nix
@@ -0,0 +1,48 @@
+{ lib
+, stdenv
+, fetchgit
+, libbsd
+, readline
+}:
+
+stdenv.mkDerivation rec {
+  pname = "rosie";
+  version = "unstable-2020-01-11";
+
+  src = fetchgit {
+    url = "https://gitlab.com/rosie-pattern-language/rosie";
+    rev = "670e9027563609ba2ea31e14e2621a1302742795";
+    sha256 = "0jc512dbn62a1fniknhbp6q0xa1p7xi3hn5v60is8sy9jgi3afxv";
+    fetchSubmodules = true;
+  };
+
+  postUnpack = ''
+    # The Makefile calls git to update submodules, unless this file exists
+    touch ${src.name}/submodules/~~present~~
+  '';
+
+  preConfigure = ''
+    patchShebangs src/build_info.sh
+    # Part of the same Makefile target which calls git to update submodules
+    ln -s src submodules/lua/include
+  '';
+
+  postInstall = ''
+    mkdir -p $out/share/emacs/site-lisp $out/share/vim-plugins $out/share/nvim
+    mv $out/lib/rosie/extra/extra/emacs/* $out/share/emacs/site-lisp/
+    mv $out/lib/rosie/extra/extra/vim $out/share/vim-plugins/rosie
+    ln -s $out/share/vim-plugins/rosie $out/share/nvim/site
+  '';
+
+  makeFlags = [ "DESTDIR=${placeholder "out"}" ];
+
+  buildInputs = [ libbsd readline ];
+
+  meta = with lib; {
+    homepage = "https://rosie-lang.org";
+    description = "Tools for searching using parsing expression grammars";
+    license = licenses.mit;
+    maintainers = with maintainers; [ kovirobi ];
+    platforms = with platforms; linux ++ darwin;
+  };
+}
diff --git a/pkgs/tools/text/rpl/default.nix b/pkgs/tools/text/rpl/default.nix
new file mode 100644
index 00000000000..1677e9c3f96
--- /dev/null
+++ b/pkgs/tools/text/rpl/default.nix
@@ -0,0 +1,38 @@
+{ lib, fetchFromGitHub, python3Packages }:
+
+python3Packages.buildPythonApplication rec {
+  pname = "rpl";
+  version = "1.10";
+
+  # Tests not included in pip package.
+  doCheck = false;
+
+
+  src = fetchFromGitHub {
+    owner = "rrthomas";
+    repo = "rpl";
+    rev = "4467bd46a7a798f738247a7f090c1505176bd597";
+    sha256 = "0yf3pc3fws4nnh4nd8d3jpglmsyi69d17qqgpcnkpqca5l4cd25w";
+  };
+
+  patches = [
+    ./remove-argparse-manpage.diff # quickfix for ImportError: No module named build_manpages.build_manpages
+  ];
+
+  buildInputs = [
+    #python3Packages.argparse-manpage # TODO
+    python3Packages.chardet
+  ];
+
+  installPhase = ''
+    mkdir -p $out/bin
+    mv rpl $out/bin
+  '';
+
+  meta = with lib; {
+    description = "Replace strings in files";
+    homepage    = "https://github.com/rrthomas/rpl";
+    license     = licenses.gpl2;
+    maintainers = with maintainers; [ teto ];
+  };
+}
diff --git a/pkgs/tools/text/rpl/remove-argparse-manpage.diff b/pkgs/tools/text/rpl/remove-argparse-manpage.diff
new file mode 100644
index 00000000000..8d329769968
--- /dev/null
+++ b/pkgs/tools/text/rpl/remove-argparse-manpage.diff
@@ -0,0 +1,27 @@
+diff --git a/setup.cfg b/setup.cfg
+index 12e9198..38e5376 100644
+--- a/setup.cfg
++++ b/setup.cfg
+@@ -15,7 +15,6 @@ classifiers =
+ [options]
+ scripts = rpl
+ python_requires = >=3
+-setup_requires = argparse-manpage
+ install_requires = chardet
+ 
+ [options.extras_require]
+diff --git a/setup.py b/setup.py
+index 96cade6..879fc44 100644
+--- a/setup.py
++++ b/setup.py
+@@ -1,9 +1,8 @@
+-from build_manpages.build_manpages import get_install_cmd
+ from setuptools import setup
+ from setuptools.command.install import install
+ 
+ setup(
+     cmdclass={
+-        'install': get_install_cmd(install),
++        'install': install,
+     }
+ )
diff --git a/pkgs/tools/text/rs/default.nix b/pkgs/tools/text/rs/default.nix
new file mode 100644
index 00000000000..9aca92922a5
--- /dev/null
+++ b/pkgs/tools/text/rs/default.nix
@@ -0,0 +1,52 @@
+{ lib, stdenv, fetchurl, libbsd }:
+
+stdenv.mkDerivation rec {
+  pname = "rs";
+  version = "20200313";
+
+  src = fetchurl {
+    url = "https://www.mirbsd.org/MirOS/dist/mir/rs/${pname}-${version}.tar.gz";
+    sha256 = "0gxwlfk7bzivpp2260w2r6gkyl7vdi05cggn1fijfnp8kzf1b4li";
+  };
+
+  buildInputs = [ libbsd ];
+
+  buildPhase = ''
+    ${stdenv.cc}/bin/cc utf8.c rs.c -o rs -lbsd
+  '';
+
+  installPhase = ''
+    install -Dm 755 rs -t $out/bin
+    install -Dm 644 rs.1 -t $out/share/man/man1
+  '';
+
+  meta = with lib; {
+    description = "Reshape a data array from standard input";
+    longDescription = ''
+      rs reads the standard input, interpreting each line as a row of blank-
+      separated entries in an array, transforms the array according to the op-
+      tions, and writes it on the standard output. With no arguments (argc < 2)
+      it transforms stream input into a columnar format convenient for terminal
+      viewing, i.e. if the length (in bytes!) of the first line is smaller than
+      the display width, -et is implied, -t otherwise.
+
+      The shape of the input array is deduced from the number of lines and the
+      number of columns on the first line. If that shape is inconvenient, a more
+      useful one might be obtained by skipping some of the input with the -k
+      option. Other options control interpretation of the input columns.
+
+      The shape of the output array is influenced by the rows and cols specifi-
+      cations, which should be positive integers. If only one of them is a po-
+      sitive integer, rs computes a value for the other which will accommodate
+      all of the data. When necessary, missing data are supplied in a manner
+      specified by the options and surplus data are deleted. There are options
+      to control presentation of the output columns, including transposition of
+      the rows and columns.
+    '';
+
+    homepage = "https://www.mirbsd.org/htman/i386/man1/rs.htm";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ AndersonTorres ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/rst2html5/default.nix b/pkgs/tools/text/rst2html5/default.nix
new file mode 100644
index 00000000000..5ae0caa34e1
--- /dev/null
+++ b/pkgs/tools/text/rst2html5/default.nix
@@ -0,0 +1,25 @@
+{ lib, python3Packages }:
+
+python3Packages.buildPythonPackage rec {
+  pname = "rst2html5";
+  version = "2.0";
+
+  src = python3Packages.fetchPypi {
+    inherit pname version;
+    hash = "sha256-Ejjja/fm6wXTf9YtjCYZsNDB8X5oAtyPoUIsYFDuZfc=";
+  };
+
+  buildInputs = with python3Packages; [
+    beautifulsoup4
+    docutils
+    genshi
+    pygments
+  ];
+
+  meta = with lib;{
+    homepage = "https://rst2html5.readthedocs.io/en/latest/";
+    description = "Converts ReSTructuredText to (X)HTML5";
+    license = licenses.mit;
+    maintainers = with maintainers; [ AndersonTorres ];
+  };
+}
diff --git a/pkgs/tools/text/ruby-zoom/Gemfile b/pkgs/tools/text/ruby-zoom/Gemfile
new file mode 100644
index 00000000000..4bb5d8c175d
--- /dev/null
+++ b/pkgs/tools/text/ruby-zoom/Gemfile
@@ -0,0 +1,2 @@
+source 'https://rubygems.org'
+gem 'ruby-zoom'
diff --git a/pkgs/tools/text/ruby-zoom/Gemfile.lock b/pkgs/tools/text/ruby-zoom/Gemfile.lock
new file mode 100644
index 00000000000..820a972d106
--- /dev/null
+++ b/pkgs/tools/text/ruby-zoom/Gemfile.lock
@@ -0,0 +1,24 @@
+GEM
+  remote: https://rubygems.org/
+  specs:
+    djinni (2.2.4)
+      fagin (~> 1.2, >= 1.2.1)
+    fagin (1.2.1)
+    hilighter (1.2.3)
+    json_config (1.1.0)
+    ruby-zoom (5.3.0)
+      djinni (~> 2.2, >= 2.2.4)
+      fagin (~> 1.2, >= 1.2.1)
+      hilighter (~> 1.2, >= 1.2.3)
+      json_config (~> 1.0, >= 1.0.0)
+      scoobydoo (~> 1.0, >= 1.0.0)
+    scoobydoo (1.0.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  ruby-zoom
+
+BUNDLED WITH
+   1.17.2
diff --git a/pkgs/tools/text/ruby-zoom/default.nix b/pkgs/tools/text/ruby-zoom/default.nix
new file mode 100644
index 00000000000..965d23d0c44
--- /dev/null
+++ b/pkgs/tools/text/ruby-zoom/default.nix
@@ -0,0 +1,18 @@
+{ lib, bundlerEnv, ruby, bundlerUpdateScript }:
+
+bundlerEnv {
+  pname = "ruby-zoom";
+
+  inherit ruby;
+  gemdir = ./.;
+
+  passthru.updateScript = bundlerUpdateScript "ruby-zoom";
+
+  meta = with lib; {
+    description = "Quickly open CLI search results in your favorite editor!";
+    homepage    = "https://gitlab.com/mjwhitta/zoom";
+    license     = with licenses; gpl3;
+    maintainers = with maintainers; [ vmandela nicknovitski ];
+    platforms   = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/ruby-zoom/gemset.nix b/pkgs/tools/text/ruby-zoom/gemset.nix
new file mode 100644
index 00000000000..19584787d90
--- /dev/null
+++ b/pkgs/tools/text/ruby-zoom/gemset.nix
@@ -0,0 +1,64 @@
+{
+  djinni = {
+    dependencies = ["fagin"];
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "18zk80jk70xq1bnsvzcgxb13x9fqdb5g4m02b2f6mvqm4cyw26pl";
+      type = "gem";
+    };
+    version = "2.2.4";
+  };
+  fagin = {
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0psyydh4hf2s1kz0r50aiyjf5v2pqhkbmy0gicxzaj5n17q2ga24";
+      type = "gem";
+    };
+    version = "1.2.1";
+  };
+  hilighter = {
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "03zm49g96dfpan5fhblcjxrzv7ldwan57sn0jcllkcmrqfd0zlyz";
+      type = "gem";
+    };
+    version = "1.2.3";
+  };
+  json_config = {
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0slb618n1ipn47j6dsxbfv2j9pl06dxn2i651llix09d529m7zwa";
+      type = "gem";
+    };
+    version = "1.1.0";
+  };
+  ruby-zoom = {
+    dependencies = ["djinni" "fagin" "hilighter" "json_config" "scoobydoo"];
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0iqxc0rzypsxy4wbxnvgvk98dbcsrcczq3xi9xd4wz4ggwq564l3";
+      type = "gem";
+    };
+    version = "5.3.0";
+  };
+  scoobydoo = {
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "162p75nc9x078kqcpdsrsd7kngs6jc5n4injz3kzpwf0jgbbm8n7";
+      type = "gem";
+    };
+    version = "1.0.0";
+  };
+}
diff --git a/pkgs/tools/text/runiq/default.nix b/pkgs/tools/text/runiq/default.nix
new file mode 100644
index 00000000000..6d7bb5e7eb0
--- /dev/null
+++ b/pkgs/tools/text/runiq/default.nix
@@ -0,0 +1,20 @@
+{ fetchCrate, lib, rustPlatform }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "runiq";
+  version = "1.2.1";
+
+  src = fetchCrate {
+    inherit pname version;
+    sha256 = "0xhd1z8mykxg9kiq8nw5agy1jxfk414czq62xm1s13ssig3h7jqj";
+  };
+
+  cargoSha256 = "1g4yfz5xq9lqwh0ggyn8kn8bnzrqfmh7kx455md5ranrqqh0x5db";
+
+  meta = with lib; {
+    description = "An efficient way to filter duplicate lines from input, à la uniq";
+    homepage = "https://github.com/whitfin/runiq";
+    license = licenses.mit;
+    maintainers = with maintainers; [ figsoda ];
+  };
+}
diff --git a/pkgs/tools/text/ruplacer/default.nix b/pkgs/tools/text/ruplacer/default.nix
new file mode 100644
index 00000000000..c882e046c3d
--- /dev/null
+++ b/pkgs/tools/text/ruplacer/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, Security }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "ruplacer";
+  version = "0.6.4";
+
+  src = fetchFromGitHub {
+    owner = "TankerHQ";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-jLGstlEqABT4ejdYlTQZaBVeYy86+lqIilyufPGIZyQ=";
+  };
+
+  cargoSha256 = "sha256-cv+g68WQvnnd0qZDB9PfZLbsdrM+RXs27a0Q5YPiHDQ=";
+
+  buildInputs = (lib.optional stdenv.isDarwin Security);
+
+  meta = with lib; {
+    description = "Find and replace text in source files";
+    homepage = "https://github.com/TankerHQ/ruplacer";
+    license = [ licenses.bsd3 ];
+    maintainers = with maintainers; [ Br1ght0ne ];
+  };
+}
diff --git a/pkgs/tools/text/rust-petname/default.nix b/pkgs/tools/text/rust-petname/default.nix
new file mode 100644
index 00000000000..f20a9e519de
--- /dev/null
+++ b/pkgs/tools/text/rust-petname/default.nix
@@ -0,0 +1,22 @@
+{ lib, rustPlatform, fetchCrate }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "rust-petname";
+  version = "1.1.2";
+
+  src = fetchCrate {
+    inherit version;
+    crateName = "petname";
+    sha256 = "sha256-DfRWGwnWVJBcbW7aPEzgPd+gfldP+ypZlk8FcPZzp8g=";
+  };
+
+  cargoSha256 = "sha256-tCVJX8NcbT+6t2kDeCMfcSDaq3O89ycj08bxTmp3JHs=";
+
+  meta = with lib; {
+    description = "Generate human readable random names";
+    homepage = "https://github.com/allenap/rust-petname";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ figsoda ];
+    mainProgram = "petname";
+  };
+}
diff --git a/pkgs/tools/text/sad/default.nix b/pkgs/tools/text/sad/default.nix
new file mode 100644
index 00000000000..0de0f745a23
--- /dev/null
+++ b/pkgs/tools/text/sad/default.nix
@@ -0,0 +1,25 @@
+{ lib
+, fetchFromGitHub
+, rustPlatform
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "sad";
+  version = "0.4.20";
+
+  src = fetchFromGitHub {
+    owner = "ms-jpq";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-BhkSqXiQPOSYnCXqjAqenKx3DextxPluqsTAMI4Xs7g=";
+  };
+
+  cargoSha256 = "sha256-aKTF0DH8Lf/H6OfQPuQ6yGOmUEUguYcHMCuYKIjNR9k=";
+
+  meta = with lib; {
+    description = "CLI tool to search and replace";
+    homepage = "https://github.com/ms-jpq/sad";
+    license = licenses.mit;
+    maintainers = with maintainers; [ fab ];
+  };
+}
diff --git a/pkgs/tools/text/schema2ldif/default.nix b/pkgs/tools/text/schema2ldif/default.nix
new file mode 100644
index 00000000000..84196ae1119
--- /dev/null
+++ b/pkgs/tools/text/schema2ldif/default.nix
@@ -0,0 +1,33 @@
+{ lib, stdenv, fetchurl, makeWrapper, perlPackages }:
+
+stdenv.mkDerivation rec {
+  pname = "schema2ldif";
+  version = "1.3";
+
+  src = fetchurl {
+    url = "https://repos.fusiondirectory.org/sources/schema2ldif/schema2ldif-${version}.tar.gz";
+    sha256 = "00cd9xx9g0mnnfn5lvay3vg166z84jla0ya1x34ljdc8bflxsr9a";
+  };
+
+  buildInputs = [ perlPackages.perl ];
+  nativeBuildInputs = [ makeWrapper ];
+
+  installPhase = ''
+    mkdir -p $out/bin $out/share/man/man1
+
+    cp bin/{schema2ldif,ldap-schema-manager} $out/bin
+    gzip -c man/schema2ldif.1 > $out/share/man/man1/schema2ldif.1.gz
+    gzip -c man/ldap-schema-manager.1 > $out/share/man/man1/ldap-schema-manager.1.gz
+
+    wrapProgram $out/bin/schema2ldif \
+       --prefix PERL5PATH : "${perlPackages.makePerlPath [ perlPackages.GetoptLong ]}"
+  '';
+
+  meta = with lib; {
+    description = "Utilities to manage schema in .schema and .ldif format";
+    homepage = "https://www.fusiondirectory.org/schema2ldif-project-and-components/";
+    license = licenses.bsd3;
+    platforms = platforms.unix;
+    maintainers = with maintainers; [ das_j ];
+  };
+}
diff --git a/pkgs/tools/text/sd/default.nix b/pkgs/tools/text/sd/default.nix
new file mode 100644
index 00000000000..009150062db
--- /dev/null
+++ b/pkgs/tools/text/sd/default.nix
@@ -0,0 +1,34 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, installShellFiles, Security
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "sd";
+  version = "0.7.6";
+
+  src = fetchFromGitHub {
+    owner = "chmln";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "0c5bsqs6c55x4j640vhzlmbiylhp5agr7lx0jrwcjazfyvxihc01";
+  };
+
+  cargoSha256 = "1iwgy9zzdxay6hb9pz47jchy03jrsy5csxijlq4i228qhqnvq1lr";
+
+  nativeBuildInputs = [ installShellFiles ];
+
+  buildInputs = lib.optionals stdenv.isDarwin [ Security ];
+
+  preFixup = ''
+    installManPage $releaseDir/build/sd-*/out/sd.1
+
+    installShellCompletion $releaseDir/build/sd-*/out/sd.{bash,fish}
+    installShellCompletion --zsh $releaseDir/build/sd-*/out/_sd
+  '';
+
+  meta = with lib; {
+    description = "Intuitive find & replace CLI (sed alternative)";
+    homepage = "https://github.com/chmln/sd";
+    license = licenses.mit;
+    maintainers = with maintainers; [ amar1729 Br1ght0ne ];
+  };
+}
diff --git a/pkgs/tools/text/sgml/jade/default.nix b/pkgs/tools/text/sgml/jade/default.nix
new file mode 100644
index 00000000000..8aeaaaa4249
--- /dev/null
+++ b/pkgs/tools/text/sgml/jade/default.nix
@@ -0,0 +1,44 @@
+{ lib, stdenv, fetchurl, gnum4 }:
+
+stdenv.mkDerivation rec {
+  pname = "jade";
+  version = "1.2.1";
+  debpatch = "47.3";
+
+  src = fetchurl {
+    url = "ftp://ftp.jclark.com/pub/jade/jade-${version}.tar.gz";
+    sha256 = "84e2f8a2a87aab44f86a46b71405d4f919b219e4c73e03a83ab6c746a674b187";
+  };
+
+  patchsrc =  fetchurl {
+    url = "mirror://debian/pool/main/j/jade/jade_${version}-${debpatch}.diff.gz";
+    sha256 = "8e94486898e3503308805f856a65ba5b499a6f21994151270aa743de48305464";
+  };
+
+  patches = [ patchsrc ];
+
+  buildInputs = [ gnum4 ];
+
+  NIX_CFLAGS_COMPILE = "-Wno-deprecated";
+
+  # Makefile is missing intra-library depends, fails build as:
+  # ld: cannot find -lsp
+  # ld: cannot find -lspgrove
+  enableParallelBuilding = false;
+
+  preInstall = ''
+    install -d -m755 "$out"/lib
+  '';
+
+  postInstall = ''
+    mv "$out/bin/sx" "$out/bin/sgml2xml"
+  '';
+
+  meta = {
+    description = "James Clark's DSSSL Engine";
+    license = "custom";
+    homepage = "http://www.jclark.com/jade/";
+    platforms = with lib.platforms; linux;
+    maintainers = with lib.maintainers; [ e-user ];
+  };
+}
diff --git a/pkgs/tools/text/sgml/openjade/default.nix b/pkgs/tools/text/sgml/openjade/default.nix
new file mode 100644
index 00000000000..f87bd5d7b1a
--- /dev/null
+++ b/pkgs/tools/text/sgml/openjade/default.nix
@@ -0,0 +1,27 @@
+{ lib, stdenv, fetchurl, opensp, perl }:
+
+stdenv.mkDerivation rec {
+  pname = "openjade";
+  version = "1.3.2";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/openjade/openjade-${version}.tar.gz";
+    sha256 = "1l92sfvx1f0wmkbvzv1385y1gb3hh010xksi1iyviyclrjb7jb8x";
+  };
+
+  patches = [ ./msggen.patch ];
+
+  buildInputs = [ opensp perl ];
+
+  configureFlags = [
+    "--enable-spincludedir=${opensp}/include/OpenSP"
+    "--enable-splibdir=${opensp}/lib"
+  ];
+
+  meta = {
+    description = "An implementation of DSSSL, an ISO standard for formatting SGML (and XML) documents";
+    license = lib.licenses.mit;
+    homepage = "http://openjade.sourceforge.net/";
+    platforms = lib.platforms.linux;
+  };
+}
diff --git a/pkgs/tools/text/sgml/openjade/msggen.patch b/pkgs/tools/text/sgml/openjade/msggen.patch
new file mode 100644
index 00000000000..d59573fa49c
--- /dev/null
+++ b/pkgs/tools/text/sgml/openjade/msggen.patch
@@ -0,0 +1,34 @@
+http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/app-text/openjade/files/openjade-1.3.2-msggen.pl.patch?revision=1.2
+
+Use Getopt::Std in place of getopts.pl.
+https://bugs.gentoo.org/show_bug.cgi?id=420083
+
+--- a/msggen.pl
++++ b/msggen.pl
+@@ -4,6 +4,7 @@
+ # See the file COPYING for copying permission.
+ 
+ use POSIX;
++use Getopt::Std;
+ 
+ # Package and version.
+ $package = 'openjade';
+@@ -18,8 +19,7 @@
+ undef $opt_l;
+ undef $opt_p;
+ undef $opt_t;
+-do 'getopts.pl';
+-&Getopts('l:p:t:');
++getopts('l:p:t:');
+ $module = $opt_l;
+ $pot_file = $opt_p;
+ 
+@@ -72,7 +72,7 @@
+     else {
+ 	$field[0] =~ /^[IWQXE][0-9]$/ || &error("invalid first field");;
+ 	$type[$num] = substr($field[0], 0, 1);
+-	$argc = int(substr($field[0], 1, 1));
++	$argc = substr($field[0], 1, 1);
+     }
+     $nargs[$num] = $argc;
+     $field[1] =~ /^[a-zA-Z_][a-zA-Z0-9_]+$/ || &error("invalid tag");
diff --git a/pkgs/tools/text/sgml/opensp/default.nix b/pkgs/tools/text/sgml/opensp/default.nix
new file mode 100644
index 00000000000..d55afbc5dd9
--- /dev/null
+++ b/pkgs/tools/text/sgml/opensp/default.nix
@@ -0,0 +1,55 @@
+{ lib, stdenv, fetchurl, fetchpatch, xmlto, docbook_xml_dtd_412
+, libxslt, docbook_xsl, autoconf, automake, gettext, libiconv, libtool
+}:
+
+stdenv.mkDerivation rec {
+  pname = "opensp";
+  version = "1.5.2";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/openjade/OpenSP-${version}.tar.gz";
+    sha256 = "1khpasr6l0a8nfz6kcf3s81vgdab8fm2dj291n5r2s53k228kx2p";
+  };
+
+  postPatch = ''
+    sed -i s,/usr/share/sgml/docbook/xml-dtd-4.1.2/,${docbook_xml_dtd_412}/xml/dtd/docbook/, \
+      docsrc/*.xml
+  '';
+
+  patches = [
+    (fetchpatch {
+      url = "https://gitweb.gentoo.org/repo/gentoo.git/plain/app-text/opensp/files/opensp-1.5.2-c11-using.patch?id=688d9675782dfc162d4e6cff04c668f7516118d0";
+      sha256 = "04q14s8qsad0bkjmj067dn831i0r6v7742rafdlnbfm5y249m2q6";
+    })
+  ];
+
+  setupHook = ./setup-hook.sh;
+
+  postFixup = ''
+    # Remove random ids in the release notes
+    sed -i -e 's/href="#idm.*"//g' $out/share/doc/OpenSP/releasenotes.html
+    sed -i -e 's/name="idm.*"//g' $out/share/doc/OpenSP/releasenotes.html
+    '';
+
+  preConfigure = lib.optionalString stdenv.isCygwin ''
+    autoreconf -fi
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    xmlto
+    docbook_xml_dtd_412
+    docbook_xsl
+  ] ++ lib.optionals stdenv.isCygwin [ autoconf automake libtool ];
+
+  doCheck = false; # fails
+
+  meta = with lib; {
+    description = "A suite of SGML/XML processing tools";
+    license = licenses.mit;
+    homepage = "http://openjade.sourceforge.net/";
+    platforms = platforms.unix;
+    maintainers = with maintainers; [ ];
+  };
+}
diff --git a/pkgs/tools/text/sgml/opensp/setup-hook.sh b/pkgs/tools/text/sgml/opensp/setup-hook.sh
new file mode 100644
index 00000000000..5bace3c6688
--- /dev/null
+++ b/pkgs/tools/text/sgml/opensp/setup-hook.sh
@@ -0,0 +1,22 @@
+addSGMLCatalogs () {
+      if test -d $1/sgml/dtd; then
+          for i in $(find $1/sgml/dtd -name docbook.cat); do
+              export SGML_CATALOG_FILES="${SGML_CATALOG_FILES:+:}$i"
+          done
+      fi
+}
+
+if test -z "${sgmlHookDone-}"; then
+    sgmlHookDone=1
+
+    # Set http_proxy and ftp_proxy to a invalid host to prevent
+    # xmllint and xsltproc from trying to download DTDs from the
+    # network even when --nonet is not given.  That would be impure.
+    # (Note that .invalid is a reserved domain guaranteed not to
+    # work.)
+    export http_proxy=http://nodtd.invalid/
+    export ftp_proxy=http://nodtd.invalid/
+
+    export SGML_CATALOG_FILES
+    addEnvHooks "$targetOffset" addSGMLCatalogs
+fi
diff --git a/pkgs/tools/text/shab/default.nix b/pkgs/tools/text/shab/default.nix
new file mode 100644
index 00000000000..b5bb98e5f4d
--- /dev/null
+++ b/pkgs/tools/text/shab/default.nix
@@ -0,0 +1,73 @@
+{ bash, stdenv, lib, runCommand, writeText, fetchFromGitHub }:
+let
+  version = "1.0.0";
+
+  shab = stdenv.mkDerivation {
+    pname = "shab";
+    inherit version;
+
+    src = fetchFromGitHub {
+      owner = "zimbatm";
+      repo = "shab";
+      rev = "v${version}";
+      sha256 = "02lf1s6plhhcfyj9xha44wij9jbphb1x5q55xj3b5bx2ji2jsvji";
+    };
+
+    postPatch = ''
+      for f in test.sh test/*.sh; do
+        patchShebangs "$f"
+      done
+    '';
+
+    doCheck = true;
+    doInstallCheck = true;
+
+    checkPhase = ''
+      ./test.sh
+    '';
+
+    installPhase = ''
+      mkdir -p $out/bin
+      cp ./shab $out/bin/shab
+    '';
+
+    installCheckPhase = ''
+      [[ "$(echo 'Hello $entity' | entity=world $out/bin/shab)" == 'Hello world' ]]
+    '';
+
+    passthru = {
+      inherit render renderText;
+    };
+
+    meta = with lib; {
+      description = "The bash templating language";
+      homepage = "https://github.com/zimbatm/shab";
+      license = licenses.unlicense;
+      maintainers = with maintainers; [ zimbatm ];
+      platforms = bash.meta.platforms;
+    };
+  };
+
+  /*
+     shabScript:       a path or filename to use as a template
+     parameters.name:  the name to use as part of the store path
+     parameters:       variables to expose to the template
+   */
+  render = shabScript: parameters:
+    let extraParams = {
+          inherit shabScript;
+        };
+    in runCommand "out" (parameters // extraParams) ''
+      ${shab}/bin/shab "$shabScript" >$out
+    '';
+
+  /*
+     shabScriptText:   a string to use as a template
+     parameters.name:  the name to use as part of the store path
+     parameters:       variables to expose to the template
+   */
+  renderText = shabScriptText: parameters:
+    render (writeText "template" shabScriptText) parameters;
+
+in
+  shab
diff --git a/pkgs/tools/text/shfmt/default.nix b/pkgs/tools/text/shfmt/default.nix
new file mode 100644
index 00000000000..061e1f709eb
--- /dev/null
+++ b/pkgs/tools/text/shfmt/default.nix
@@ -0,0 +1,37 @@
+{ lib, buildGoModule, fetchFromGitHub, installShellFiles, scdoc }:
+
+buildGoModule rec {
+  pname = "shfmt";
+  version = "3.4.3";
+
+  src = fetchFromGitHub {
+    owner = "mvdan";
+    repo = "sh";
+    rev = "v${version}";
+    sha256 = "sha256-tE7U/hE1Z/9VZTYt2jU0IE11cS01l6wTPVFuXH36sM4=";
+  };
+
+  vendorSha256 = "sha256-ZYsQ+wE+G7xNrBN29npSxxPCz9+Wb/RsBzM5uwJkhO8=";
+
+  subPackages = [ "cmd/shfmt" ];
+
+  ldflags = [ "-s" "-w" "-X main.version=${version}" ];
+
+  nativeBuildInputs = [ installShellFiles scdoc ];
+
+  postBuild = ''
+    scdoc < cmd/shfmt/shfmt.1.scd > shfmt.1
+    installManPage shfmt.1
+  '';
+
+  meta = with lib; {
+    homepage = "https://github.com/mvdan/sh";
+    description = "A shell parser and formatter";
+    longDescription = ''
+      shfmt formats shell programs. It can use tabs or any number of spaces to indent.
+      You can feed it standard input, any number of files or any number of directories to recurse into.
+    '';
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ zowoq SuperSandro2000 ];
+  };
+}
diff --git a/pkgs/tools/text/shocco/default.nix b/pkgs/tools/text/shocco/default.nix
new file mode 100644
index 00000000000..1359db98978
--- /dev/null
+++ b/pkgs/tools/text/shocco/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchFromGitHub, perlPackages, python3 }:
+
+stdenv.mkDerivation rec {
+  pname = "shocco";
+  version = "1.0";
+
+  src = fetchFromGitHub {
+    owner = "rtomayko";
+    repo = "shocco";
+    rev = version;
+    sha256 = "1nkwcw9fqf4vyrwidqi6by7nrmainkjqkirkz3yxmzk6kzwr38mi";
+  };
+
+  prePatch = ''
+    # Don't change $PATH
+    substituteInPlace configure --replace PATH= NIRVANA=
+  '';
+
+  buildInputs = [ perlPackages.TextMarkdown python3.pkgs.pygments ];
+
+  meta = with lib; {
+    description = "A quick-and-dirty, literate-programming-style documentation generator for / in POSIX shell";
+    homepage = "https://rtomayko.github.io/shocco/";
+    license = licenses.mit;
+    platforms = platforms.all;
+    maintainers = with maintainers; [ dotlambda ];
+  };
+}
diff --git a/pkgs/tools/text/sift/default.nix b/pkgs/tools/text/sift/default.nix
new file mode 100644
index 00000000000..dc025f17a78
--- /dev/null
+++ b/pkgs/tools/text/sift/default.nix
@@ -0,0 +1,25 @@
+{ lib, buildGoPackage, fetchFromGitHub }:
+
+buildGoPackage rec {
+  pname = "sift";
+  version = "0.9.0";
+  rev = "v${version}";
+
+  goPackagePath = "github.com/svent/sift";
+
+  src = fetchFromGitHub {
+    inherit rev;
+    owner = "svent";
+    repo = "sift";
+    sha256 = "0bgy0jf84z1c3msvb60ffj4axayfchdkf0xjnsbx9kad1v10g7i1";
+  };
+
+  goDeps = ./deps.nix;
+
+  meta = with lib; {
+    description = "A fast and powerful alternative to grep";
+    homepage = "https://sift-tool.org";
+    maintainers = [ maintainers.carlsverre ];
+    license = licenses.gpl3;
+  };
+}
diff --git a/pkgs/tools/text/sift/deps.nix b/pkgs/tools/text/sift/deps.nix
new file mode 100644
index 00000000000..038555fa3ca
--- /dev/null
+++ b/pkgs/tools/text/sift/deps.nix
@@ -0,0 +1,29 @@
+[
+  {
+    goPackagePath = "golang.org/x/crypto";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/crypto";
+      rev = "575fdbe86e5dd89229707ebec0575ce7d088a4a6";
+      sha256 = "1kgv1mkw9y404pk3lcwbs0vgl133mwyp294i18jg9hp10s5d56xa";
+    };
+  }
+  {
+    goPackagePath = "github.com/svent/go-flags";
+    fetch = {
+      type = "git";
+      url = "https://github.com/svent/go-flags";
+      rev = "4bcbad344f0318adaf7aabc16929701459009aa3";
+      sha256 = "1gb416fgxl9gq4q6wsv3i2grq1mzbi7lvfvmfdqbxqbv9vizzh34";
+    };
+  }
+  {
+    goPackagePath = "github.com/svent/go-nbreader";
+    fetch = {
+      type = "git";
+      url = "https://github.com/svent/go-nbreader";
+      rev = "7cef48da76dca6a496faa7fe63e39ed665cbd219";
+      sha256 = "0hw11jj5r3f6qwydg41nc3c6aadlbkhc1qpxra2609lis0qa9h4r";
+    };
+  }
+]
diff --git a/pkgs/tools/text/silver-searcher/bash-completion.patch b/pkgs/tools/text/silver-searcher/bash-completion.patch
new file mode 100644
index 00000000000..30e8c72389b
--- /dev/null
+++ b/pkgs/tools/text/silver-searcher/bash-completion.patch
@@ -0,0 +1,5 @@
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -9 +9 @@
+-bashcompdir = $(pkgdatadir)/completions
++bashcompdir = $(datadir)/bash-completion/completions
diff --git a/pkgs/tools/text/silver-searcher/default.nix b/pkgs/tools/text/silver-searcher/default.nix
new file mode 100644
index 00000000000..757c65eed84
--- /dev/null
+++ b/pkgs/tools/text/silver-searcher/default.nix
@@ -0,0 +1,29 @@
+{lib, stdenv, fetchFromGitHub, autoreconfHook, pkg-config, pcre, zlib, xz}:
+
+stdenv.mkDerivation rec {
+  pname = "silver-searcher";
+  version = "2.2.0";
+
+  src = fetchFromGitHub {
+    owner = "ggreer";
+    repo = "the_silver_searcher";
+    rev = version;
+    sha256 = "0cyazh7a66pgcabijd27xnk1alhsccywivv6yihw378dqxb22i1p";
+  };
+
+  patches = [ ./bash-completion.patch ];
+
+  NIX_LDFLAGS = lib.optionalString stdenv.isLinux "-lgcc_s";
+
+  nativeBuildInputs = [ autoreconfHook pkg-config ];
+  buildInputs = [ pcre zlib xz ];
+
+  meta = with lib; {
+    homepage = "https://github.com/ggreer/the_silver_searcher/";
+    description = "A code-searching tool similar to ack, but faster";
+    maintainers = with maintainers; [ madjar ];
+    mainProgram = "ag";
+    platforms = platforms.all;
+    license = licenses.asl20;
+  };
+}
diff --git a/pkgs/tools/text/smu/default.nix b/pkgs/tools/text/smu/default.nix
new file mode 100644
index 00000000000..02a29a91f47
--- /dev/null
+++ b/pkgs/tools/text/smu/default.nix
@@ -0,0 +1,28 @@
+{ stdenv, lib, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "smu";
+  version = "1.5";
+
+  src = fetchFromGitHub {
+    owner = "Gottox";
+    repo = "smu";
+    rev = "v${version}";
+    sha256 = "1jm7lhnzjx4q7gcwlkvsbffcy0zppywyh50d71ami6dnq182vvcc";
+  };
+
+  # _FORTIFY_SOURCE requires compiling with optimization (-O)
+  NIX_CFLAGS_COMPILE = "-O";
+
+  makeFlags = [
+    "PREFIX=${placeholder "out"}"
+  ];
+
+  meta = with lib; {
+    description = "simple markup - markdown like syntax";
+    homepage = "https://github.com/Gottox/smu";
+    license = licenses.mit;
+    maintainers = with maintainers; [ oxzi ];
+  };
+}
+
diff --git a/pkgs/tools/text/snippetpixie/default.nix b/pkgs/tools/text/snippetpixie/default.nix
new file mode 100644
index 00000000000..a83135b5024
--- /dev/null
+++ b/pkgs/tools/text/snippetpixie/default.nix
@@ -0,0 +1,91 @@
+{ lib, stdenv
+, fetchFromGitHub
+, nix-update-script
+, meson
+, ninja
+, vala
+, pkg-config
+, wrapGAppsHook
+, appstream
+, desktop-file-utils
+, python3
+, libgee
+, glib
+, gtk3
+, sqlite
+, at-spi2-atk
+, at-spi2-core
+, dbus
+, ibus
+, json-glib
+, pantheon
+, xorg
+}:
+
+stdenv.mkDerivation rec {
+  pname = "snippetpixie";
+  version = "1.5.3";
+
+  src = fetchFromGitHub {
+    owner = "bytepixie";
+    repo = pname;
+    rev = version;
+    sha256 = "0gs3d9hdywg4vcfbp4qfcagfjqalfgw9xpvywg4pw1cm3rzbdqmz";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    vala
+    pkg-config
+    wrapGAppsHook
+    appstream
+    desktop-file-utils
+    python3
+  ];
+
+  buildInputs = [
+    libgee
+    glib
+    gtk3
+    sqlite
+    at-spi2-atk
+    at-spi2-core
+    dbus
+    ibus
+    json-glib
+    xorg.libXtst
+    pantheon.granite
+  ];
+
+  doCheck = true;
+
+  postPatch = ''
+    chmod +x meson/post_install.py
+    patchShebangs meson/post_install.py
+  '';
+
+  passthru = {
+    updateScript = nix-update-script {
+      attrPath = pname;
+    };
+  };
+
+  meta = with lib; {
+    description = "Your little expandable text snippet helper";
+    longDescription = ''
+      Your little expandable text snippet helper.
+
+      Save your often used text snippets and then expand them whenever you type their abbreviation.
+
+      For example:- "spr`" expands to "Snippet Pixie rules!"
+
+      For non-accessible applications such as browsers and Electron apps, there's a shortcut (default is Ctrl+`) for opening a search window that pastes the selected snippet.
+    '';
+    homepage = "https://www.snippetpixie.com";
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [ ianmjones ] ++ teams.pantheon.members;
+    platforms = platforms.linux;
+    mainProgram = "com.github.bytepixie.snippetpixie";
+  };
+}
diff --git a/pkgs/tools/text/source-highlight/default.nix b/pkgs/tools/text/source-highlight/default.nix
new file mode 100644
index 00000000000..289740854f2
--- /dev/null
+++ b/pkgs/tools/text/source-highlight/default.nix
@@ -0,0 +1,63 @@
+{ lib, stdenv, fetchpatch, fetchurl, boost }:
+
+stdenv.mkDerivation rec {
+  pname = "source-highlight";
+  version = "3.1.9";
+
+  outputs = [ "out" "doc" "dev" ];
+
+  src = fetchurl {
+    url = "mirror://gnu/src-highlite/${pname}-${version}.tar.gz";
+    sha256 = "148w47k3zswbxvhg83z38ifi85f9dqcpg7icvvw1cm6bg21x4zrs";
+  };
+
+  patches = [
+    # gcc-11 compat upstream patch
+    (fetchpatch {
+      url = "http://git.savannah.gnu.org/cgit/src-highlite.git/patch/?id=904949c9026cb772dc93fbe0947a252ef47127f4";
+      sha256 = "1wnj0jmkmrwjww7qk9dvfxh8h06jdn7mi8v2fvwh95b6x87z5l47";
+      excludes = [ "ChangeLog" ];
+    })
+
+    # Upstream fix for clang-13 and gcc-12 test support
+    (fetchpatch {
+      name = "gcc-12.patch";
+      url = "http://git.savannah.gnu.org/cgit/src-highlite.git/patch/?id=ab9fe5cb9b85c5afab94f2a7f4b6d7d473c14ee9";
+      sha256 = "1v33zd2766k7cdgmajw2lffw9wd7v4f8z01f40z53f6bp608nr62";
+    })
+  ];
+
+  # source-highlight uses it's own binary to generate documentation.
+  # During cross-compilation, that binary was built for the target
+  # platform architecture, so it can't run on the build host.
+  postPatch = lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
+    substituteInPlace Makefile.in --replace "src doc tests" "src tests"
+  '';
+
+  strictDeps = true;
+  buildInputs = [ boost ];
+
+  configureFlags = [
+    "--with-boost=${boost.out}"
+    "--with-bash-completion=${placeholder "out"}/share/bash_completion.d"
+  ];
+
+  doCheck = true;
+
+  enableParallelBuilding = true;
+  # Upstream uses the same intermediate files in multiple tests, running
+  # them in parallel by make will eventually break one or more tests.
+  enableParallelChecking = false;
+
+  meta = with lib; {
+    description = "Source code renderer with syntax highlighting";
+    longDescription = ''
+      GNU Source-highlight, given a source file, produces a document
+      with syntax highlighting.
+    '';
+    homepage = "https://www.gnu.org/software/src-highlite/";
+    license = licenses.gpl3Plus;
+    platforms = platforms.unix;
+    maintainers = with maintainers; [ SuperSandro2000 ];
+  };
+}
diff --git a/pkgs/tools/text/tab/default.nix b/pkgs/tools/text/tab/default.nix
new file mode 100644
index 00000000000..18d3e3d004a
--- /dev/null
+++ b/pkgs/tools/text/tab/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, fetchFromGitHub, python3 }:
+
+stdenv.mkDerivation rec {
+  version = "9.0";
+  pname = "tab";
+
+  src = fetchFromGitHub {
+    owner = "ivan-tkatchev";
+    repo = pname;
+    rev = version;
+    sha256 = "sha256-2keVGPRYV2KCeJ+LgAcl74cjW5wvp6Rmy7VNMtdliBE=";
+  };
+
+  checkInputs = [ python3 ];
+
+  doCheck = !stdenv.isDarwin;
+
+  preCheck = ''
+    substituteInPlace Makefile --replace "python2 go2.py" "python go.py"
+  '';
+
+  checkTarget = "test";
+
+  installPhase = ''
+    runHook preInstall
+
+    install -Dm555 -t $out/bin tab
+    install -Dm444 -t $out/share/doc/tab docs/*.html
+
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Programming language/shell calculator";
+    homepage    = "https://tkatchev.bitbucket.io/tab/";
+    license     = licenses.boost;
+    maintainers = with maintainers; [ mstarzyk ];
+    platforms   = with platforms; unix;
+  };
+}
diff --git a/pkgs/tools/text/tidy-viewer/default.nix b/pkgs/tools/text/tidy-viewer/default.nix
new file mode 100644
index 00000000000..43b38d06b92
--- /dev/null
+++ b/pkgs/tools/text/tidy-viewer/default.nix
@@ -0,0 +1,29 @@
+{ lib, rustPlatform, fetchFromGitHub }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "tidy-viewer";
+  version = "1.4.3";
+
+  src = fetchFromGitHub {
+    owner = "alexhallam";
+    repo = "tv";
+    rev = version;
+    sha256 = "sha256-onLu4XNe3sLfZ273Hq9IvgZEV9ir8oEXX7tQG75K2Hw=";
+  };
+
+  cargoSha256 = "sha256-CYiRi6ny0wzTddpjdnnMHGqcWRM9wVjF34RmETgLH5A=";
+
+  # this test parses command line arguments
+  # error: Found argument '--test-threads' which wasn't expected, or isn't valid in this context
+  checkFlags = [
+    "--skip=build_reader_can_create_reader_without_file_specified"
+  ];
+
+  meta = with lib; {
+    description = "A cross-platform CLI csv pretty printer that uses column styling to maximize viewer enjoyment";
+    homepage = "https://github.com/alexhallam/tv";
+    changelog = "https://github.com/alexhallam/tv/blob/${version}/CHANGELOG.md";
+    license = licenses.unlicense;
+    maintainers = with maintainers; [ figsoda ];
+  };
+}
diff --git a/pkgs/tools/text/transifex-client/default.nix b/pkgs/tools/text/transifex-client/default.nix
new file mode 100644
index 00000000000..1174c2f382e
--- /dev/null
+++ b/pkgs/tools/text/transifex-client/default.nix
@@ -0,0 +1,32 @@
+{ lib, buildPythonApplication, fetchPypi
+, python-slugify, requests, urllib3, six, setuptools, GitPython }:
+
+buildPythonApplication rec {
+  pname = "transifex-client";
+  version = "0.14.4";
+
+  propagatedBuildInputs = [
+    urllib3 requests python-slugify six setuptools GitPython
+  ];
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "11dc95cefe90ebf0cef3749c8c7d85b9d389c05bd0e3389bf117685df562bd5c";
+  };
+
+  # https://github.com/transifex/transifex-client/issues/323
+  prePatch = ''
+    substituteInPlace requirements.txt \
+      --replace "python-slugify<5.0.0" "python-slugify"
+  '';
+
+  # Requires external resources
+  doCheck = false;
+
+  meta = with lib; {
+    homepage = "https://www.transifex.com/";
+    license = licenses.gpl2Only;
+    description = "Transifex translation service client";
+    maintainers = with maintainers; [ sikmir ];
+  };
+}
diff --git a/pkgs/tools/text/tv/default.nix b/pkgs/tools/text/tv/default.nix
new file mode 100644
index 00000000000..686433ff429
--- /dev/null
+++ b/pkgs/tools/text/tv/default.nix
@@ -0,0 +1,23 @@
+{ fetchFromGitHub, lib, rustPlatform }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "tv";
+  version = "0.7.0";
+
+  src = fetchFromGitHub {
+    owner = "uzimaru0000";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-qODv45smZ6jHCJBaa6EEvFLG+7g+FWrRf6BiHRFLzqM=";
+  };
+
+  cargoSha256 = "sha256-nI4n4KMPLaIF978b5VvW3mb02vKW+r39nllrhukJilI=";
+
+  meta = with lib; {
+    description = "Format json into table view";
+    homepage = "https://github.com/uzimaru0000/tv";
+    changelog = "https://github.com/uzimaru0000/tv/blob/v${version}/CHANGELOG.md";
+    license = licenses.mit;
+    maintainers = with maintainers; [ figsoda ];
+  };
+}
diff --git a/pkgs/tools/text/txt2tags/default.nix b/pkgs/tools/text/txt2tags/default.nix
new file mode 100644
index 00000000000..9f237066d7c
--- /dev/null
+++ b/pkgs/tools/text/txt2tags/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, fetchurl, python2 }:
+
+stdenv.mkDerivation rec {
+  version = "2.6";
+  pname = "txt2tags";
+
+  dontBuild = true;
+
+  # Python script, needs the interpreter
+  propagatedBuildInputs = [ python2 ];
+
+  installPhase = ''
+    mkdir -p "$out/bin"
+    mkdir -p "$out/share/doc"
+    mkdir -p "$out/share/man/man1/"
+    sed '1s|/usr/bin/env python|${python2}/bin/python|' < txt2tags > "$out/bin/txt2tags"
+    chmod +x "$out/bin/txt2tags"
+    gzip - < doc/manpage.man > "$out/share/man/man1/txt2tags.1.gz"
+    cp doc/userguide.pdf "$out/share/doc"
+    cp -r extras/ samples/ test/ "$out/share"
+  '';
+
+  src = fetchurl {
+    url = "http://txt2tags.googlecode.com/files/${pname}-${version}.tgz";
+    sha256 = "0p5hql559pk8v5dlzgm75yrcxwvz4z30f1q590yzng0ghvbnf530";
+  };
+
+  meta = {
+    homepage = "https://txt2tags.org/";
+    description = "A KISS markup language";
+    license  = lib.licenses.gpl2;
+    maintainers = with lib.maintainers; [ kovirobi ];
+    platforms = with lib.platforms; unix;
+  };
+}
diff --git a/pkgs/tools/text/ucg/default.nix b/pkgs/tools/text/ucg/default.nix
new file mode 100644
index 00000000000..d19379477d6
--- /dev/null
+++ b/pkgs/tools/text/ucg/default.nix
@@ -0,0 +1,58 @@
+{ lib, stdenv
+, fetchFromGitHub
+, pkg-config
+, autoreconfHook
+, pcre
+}:
+
+stdenv.mkDerivation rec {
+  pname = "ucg";
+  version = "0.3.3+date=2019-02-25";
+
+  src = fetchFromGitHub {
+    owner = "gvansickle";
+    repo = pname;
+    rev = "c3a67632f1e3f332bfb102f0db167f34a2e42da7";
+    sha256 = "sha256-/wU1PmI4ejlv7gZzZNasgROYXFiDiIxE9BFoCo6+G5Y=";
+  };
+
+  nativeBuildInputs = [
+    autoreconfHook
+    pkg-config
+  ];
+
+  buildInputs = [
+    pcre
+  ];
+
+  doInstallCheck = true;
+  installCheckPhase = ''
+    runHook preInstallCheck
+
+    testFile=$(mktemp /tmp/ucg-test.XXXX)
+    echo -ne 'Lorem ipsum dolor sit amet\n2.7182818284590' > $testFile
+    $out/bin/ucg 'dolor' $testFile || { rm $testFile; exit -1; }
+    $out/bin/ucg --ignore-case 'lorem' $testFile || { rm $testFile; exit -1; }
+    $out/bin/ucg --word-regexp '2718' $testFile && { rm $testFile; exit -1; }
+    $out/bin/ucg 'pisum' $testFile && { rm $testFile; exit -1; }
+    rm $testFile
+
+    runHook postInstallCheck
+  '';
+
+  meta = with lib; {
+    homepage = "https://github.com/gvansickle/ucg/";
+    description = "Grep-like tool for searching large bodies of source code";
+    longDescription = ''
+      UniversalCodeGrep (ucg) is an extremely fast grep-like tool specialized
+      for searching large bodies of source code. It is intended to be largely
+      command-line compatible with Ack, to some extent with ag, and where
+      appropriate with grep. Search patterns are specified as PCRE regexes.
+    '';
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ AndersonTorres ];
+    platforms = with platforms; unix;
+    broken = stdenv.isAarch64; # cpuid.h: no such file or directory
+  };
+}
+# TODO: report upstream
diff --git a/pkgs/tools/text/ugrep/default.nix b/pkgs/tools/text/ugrep/default.nix
new file mode 100644
index 00000000000..8fc299fa6c0
--- /dev/null
+++ b/pkgs/tools/text/ugrep/default.nix
@@ -0,0 +1,39 @@
+{ lib
+, stdenv
+, fetchFromGitHub
+, boost
+, bzip2
+, lz4
+, pcre2
+, xz
+, zlib
+}:
+
+stdenv.mkDerivation rec {
+  pname = "ugrep";
+  version = "3.7.1";
+
+  src = fetchFromGitHub {
+    owner = "Genivia";
+    repo = pname;
+    rev = "v${version}";
+    hash = "sha256-5ZlZ/nCUOiyOWagF1Vla945d7zKbMsHp56ZE4HwdEP4=";
+  };
+
+  buildInputs = [
+    boost
+    bzip2
+    lz4
+    pcre2
+    xz
+    zlib
+  ];
+
+  meta = with lib; {
+    description = "Ultra fast grep with interactive query UI";
+    homepage = "https://github.com/Genivia/ugrep";
+    maintainers = with maintainers; [ numkem ];
+    license = licenses.bsd3;
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/uni2ascii/default.nix b/pkgs/tools/text/uni2ascii/default.nix
new file mode 100644
index 00000000000..d83e9393f94
--- /dev/null
+++ b/pkgs/tools/text/uni2ascii/default.nix
@@ -0,0 +1,41 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "uni2ascii";
+  version = "4.18";
+
+  src = fetchurl {
+    url = "https://billposer.org/Software/Downloads/uni2ascii-${version}.tar.gz";
+    sha256 = "03lklnzr6ngs4wqiqa7rifd246f441gfvardbsaa5l6fn9pbn94y";
+  };
+
+  meta = {
+    license = lib.licenses.gpl3;
+    homepage = "http://billposer.org/Software/uni2ascii.html";
+    description = "Converts between UTF-8 and many 7-bit ASCII equivalents and back";
+
+    longDescription = ''
+    This package provides conversion in both directions between UTF-8
+    Unicode and more than thirty 7-bit ASCII equivalents, including
+    RFC 2396 URI format and RFC 2045 Quoted Printable format, the
+    representations used in HTML, SGML, XML, OOXML, the Unicode
+    standard, Rich Text Format, POSIX portable charmaps, POSIX locale
+    specifications, and Apache log files, and the escapes used for
+    including Unicode in Ada, C, Common Lisp, Java, Pascal, Perl,
+    Postscript, Python, Scheme, and Tcl.
+
+    Such ASCII equivalents are useful when including Unicode text in
+    program source, when debugging, and when entering text into web
+    programs that can handle the Unicode character set but are not
+    8-bit safe. For example, MovableType, the blog software, truncates
+    posts as soon as it encounters a byte with the high bit
+    set. However, if Unicode is entered in the form of HTML numeric
+    character entities, Movable Type will not garble the post.
+
+    It also provides ways of converting non-ASCII characters to
+    similar ASCII characters, e.g. by stripping diacritics.
+    '';
+    maintainers = with lib.maintainers; [ goibhniu ];
+    platforms = lib.platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/uniscribe/Gemfile b/pkgs/tools/text/uniscribe/Gemfile
new file mode 100644
index 00000000000..9bc158c5435
--- /dev/null
+++ b/pkgs/tools/text/uniscribe/Gemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem "uniscribe"
diff --git a/pkgs/tools/text/uniscribe/Gemfile.lock b/pkgs/tools/text/uniscribe/Gemfile.lock
new file mode 100644
index 00000000000..ee6dc316669
--- /dev/null
+++ b/pkgs/tools/text/uniscribe/Gemfile.lock
@@ -0,0 +1,37 @@
+GEM
+  remote: https://rubygems.org/
+  specs:
+    characteristics (1.4.0)
+      unicode-categories (~> 1.7)
+    paint (2.2.1)
+    rationalist (2.0.1)
+    symbolify (1.4.0)
+      characteristics (>= 0.8, < 2.0)
+    unicode-categories (1.7.0)
+    unicode-display_width (2.1.0)
+    unicode-emoji (2.9.0)
+      unicode-version (~> 1.0)
+    unicode-name (1.10.0)
+      unicode-types (~> 1.7)
+    unicode-sequence_name (1.10.0)
+    unicode-types (1.7.0)
+    unicode-version (1.1.0)
+    uniscribe (1.7.0)
+      characteristics (~> 1.4)
+      paint (>= 0.9, < 3.0)
+      rationalist (~> 2.0, >= 2.0.1)
+      symbolify (~> 1.4)
+      unicode-display_width (~> 2.1)
+      unicode-emoji (~> 2.9)
+      unicode-name (~> 1.10)
+      unicode-sequence_name (~> 1.10)
+      unicode-version (~> 1.1)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  uniscribe
+
+BUNDLED WITH
+   2.1.4
diff --git a/pkgs/tools/text/uniscribe/default.nix b/pkgs/tools/text/uniscribe/default.nix
new file mode 100644
index 00000000000..e7b9cedd2b8
--- /dev/null
+++ b/pkgs/tools/text/uniscribe/default.nix
@@ -0,0 +1,30 @@
+{ stdenv, lib, bundlerEnv, bundlerUpdateScript, makeWrapper }:
+
+let
+  rubyEnv = bundlerEnv {
+    name = "uniscribe";
+    gemdir = ./.;
+  };
+in
+stdenv.mkDerivation rec {
+  pname = "uniscribe";
+  version = (import ./gemset.nix).uniscribe.version;
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  dontUnpack = true;
+
+  installPhase = ''
+    mkdir -p $out/bin
+    makeWrapper ${rubyEnv}/bin/uniscribe $out/bin/uniscribe
+  '';
+
+  passthru.updateScript = bundlerUpdateScript "uniscribe";
+
+  meta = with lib; {
+    description = "Explains Unicode characters/code points: Displays their name, category, and shows compositions";
+    homepage = "https://github.com/janlelis/uniscribe";
+    license = licenses.mit;
+    maintainers = with maintainers; [ kjeremy ];
+  };
+}
diff --git a/pkgs/tools/text/uniscribe/gemset.nix b/pkgs/tools/text/uniscribe/gemset.nix
new file mode 100644
index 00000000000..d61123585c2
--- /dev/null
+++ b/pkgs/tools/text/uniscribe/gemset.nix
@@ -0,0 +1,1766 @@
+{
+  characteristics = {
+    dependencies = ["unicode-categories"];
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1zhgx2h89kfm1xdgfw78vyw6mgwca1nqd67hk13pfz8ffkig2ziq";
+      type = "gem";
+    };
+    version = "1.4.0";
+  };
+  paint = {
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "01fhvxdaqngldqa7r0jgnskr4iv2x2i0n3z28za8j4qszpvlcb7x";
+      type = "gem";
+    };
+    version = "2.2.1";
+  };
+  rationalist = {
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1zydr81pc63m7i5f5s51ryksv3g2qya5pd42s09v9ixk3fddpxgi";
+      type = "gem";
+    };
+    version = "2.0.1";
+  };
+  symbolify = {
+    dependencies = ["characteristics"];
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0cjalbjgw50bwna2gyjczx42nszifslijy43bmiahn4dw76jz653";
+      type = "gem";
+    };
+    version = "1.4.0";
+  };
+  unicode-categories = {
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0prakys8s56hh56q2r4gm2iigq9wk4ywwpv9ywcyi4xr9k2pliy3";
+      type = "gem";
+    };
+    version = "1.7.0";
+  };
+  unicode-display_width = {
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0csjm9shhfik0ci9mgimb7hf3xgh7nx45rkd9rzgdz6vkwr8rzxn";
+      type = "gem";
+    };
+    version = "2.1.0";
+  };
+  unicode-emoji = {
+    dependencies = ["unicode-version"];
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0fvm7z6s9nipbwsq4xqqz443g3x5lwkcpg7iwqxs9x43dd9r8h77";
+      type = "gem";
+    };
+    version = "2.9.0";
+  };
+  unicode-name = {
+    dependencies = ["unicode-types"];
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "18ly2yy1jbdcvxgfyn2n17c2v54n9llzvr7klbfhy285lz1ylkdd";
+      type = "gem";
+    };
+    version = "1.10.0";
+  };
+  unicode-sequence_name = {
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1fm57j4yplfsdq5pyxdp7pgp5adisdh8hr1dgvr5g1x076bvis16";
+      type = "gem";
+    };
+    version = "1.10.0";
+  };
+  unicode-types = {
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0qrbvx01v1x931czvrng0hvlhyb1bwa3mnq008lq5w75ldrpyiis";
+      type = "gem";
+    };
+    version = "1.7.0";
+  };
+  unicode-version = {
+    groups = ["default"];
+    platforms = [{
+      engine = "maglev";
+    } {
+      engine = "maglev";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.8";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "1.9";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.0";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.1";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.2";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.3";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.4";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.5";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "maglev";
+      version = "2.6";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+    } {
+      engine = "rbx";
+      version = "1.8";
+    } {
+      engine = "rbx";
+      version = "1.9";
+    } {
+      engine = "rbx";
+      version = "2.0";
+    } {
+      engine = "rbx";
+      version = "2.1";
+    } {
+      engine = "rbx";
+      version = "2.2";
+    } {
+      engine = "rbx";
+      version = "2.3";
+    } {
+      engine = "rbx";
+      version = "2.4";
+    } {
+      engine = "rbx";
+      version = "2.5";
+    } {
+      engine = "rbx";
+      version = "2.6";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.8";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "1.9";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.0";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.1";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.2";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.3";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.4";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.5";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    } {
+      engine = "ruby";
+      version = "2.6";
+    }];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0isqdyqix8gh2xkpy9ab7bhwwz4nc7zrv49l0kb0hqd7n3ip9zmg";
+      type = "gem";
+    };
+    version = "1.1.0";
+  };
+  uniscribe = {
+    dependencies = ["characteristics" "paint" "rationalist" "symbolify" "unicode-display_width" "unicode-emoji" "unicode-name" "unicode-sequence_name" "unicode-version"];
+    groups = ["default"];
+    platforms = [];
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0k66h24waqy51yfqkb1iish0kc3ky85h51dikzdhk6i51q2vrx7i";
+      type = "gem";
+    };
+    version = "1.7.0";
+  };
+}
diff --git a/pkgs/tools/text/unoconv/default.nix b/pkgs/tools/text/unoconv/default.nix
new file mode 100644
index 00000000000..9f3375c7e41
--- /dev/null
+++ b/pkgs/tools/text/unoconv/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, fetchFromGitHub, python3, libreoffice-unwrapped, asciidoc, makeWrapper
+# whether to install odt2pdf/odt2doc/... symlinks to unoconv
+, installSymlinks ? true
+}:
+
+# IMPORTANT: unoconv must use the same python version as libreoffice (unless it
+# will not be able to load the pyuno module from libreoffice).
+
+stdenv.mkDerivation rec {
+  pname = "unoconv";
+  version = "0.9.0";
+
+  src = fetchFromGitHub {
+    owner = "unoconv";
+    repo = "unoconv";
+    rev = version;
+    sha256 = "1akx64686in8j8arl6vsgp2n3bv770q48pfv283c6fz6wf9p8fvr";
+  };
+
+  nativeBuildInputs = [ asciidoc makeWrapper ];
+
+  preBuild = ''
+    makeFlags=prefix="$out"
+  '';
+
+  postInstall = ''
+    sed -i "s|/usr/bin/env python.*|${python3}/bin/${python3.executable}|" "$out/bin/unoconv"
+    wrapProgram "$out/bin/unoconv" --set UNO_PATH "${libreoffice-unwrapped}/lib/libreoffice/program/"
+  '' + (if installSymlinks then ''
+    make install-links prefix="$out"
+  '' else "");
+
+  meta = with lib; {
+    description = "Convert between any document format supported by LibreOffice/OpenOffice";
+    homepage = "http://dag.wieers.com/home-made/unoconv/";
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+    maintainers = [ maintainers.bjornfor ];
+  };
+}
diff --git a/pkgs/tools/text/unrtf/default.nix b/pkgs/tools/text/unrtf/default.nix
new file mode 100644
index 00000000000..3357404a7d3
--- /dev/null
+++ b/pkgs/tools/text/unrtf/default.nix
@@ -0,0 +1,31 @@
+{ lib, stdenv, fetchurl, autoconf, automake, libiconv }:
+
+stdenv.mkDerivation rec {
+  pname = "unrtf";
+  version = "0.21.10";
+
+  src = fetchurl {
+    url = "https://ftp.gnu.org/gnu/${pname}/${pname}-${version}.tar.gz";
+    sha256 = "1bil6z4niydz9gqm2j861dkxmqnpc8m7hvidsjbzz7x63whj17xl";
+  };
+
+  nativeBuildInputs = [ autoconf automake ];
+
+  buildInputs = [ libiconv ];
+
+  preConfigure = "./bootstrap";
+
+  outputs = [ "out" "man" ];
+
+  meta = with lib; {
+    description = "A converter from Rich Text Format to other formats";
+    longDescription = ''
+      UnRTF converts documents in Rich Text Format to other
+      formats, including HTML, LaTeX, and RTF itself.
+    '';
+    homepage = "https://www.gnu.org/software/unrtf/";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ joachifm ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/untex/default.nix b/pkgs/tools/text/untex/default.nix
new file mode 100644
index 00000000000..55cf01d698f
--- /dev/null
+++ b/pkgs/tools/text/untex/default.nix
@@ -0,0 +1,29 @@
+{ lib, stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "untex";
+  version = "1.3";
+
+  src = fetchurl {
+    url = "ftp://ftp.thp.uni-duisburg.de/pub/source/${pname}-${version}.tar.gz";
+    sha256 = "1jww43pl9qvg6kwh4h8imp966fzd62dk99pb4s93786lmp3kgdjv";
+  };
+
+  hardeningDisable = [ "format" ];
+
+  unpackPhase = "tar xf $src";
+  installTargets = [ "install" "install.man" ];
+  installFlags = [ "BINDIR=$(out)/bin" "MANDIR=$(out)/share/man/man1" ];
+  preBuild = ''
+    sed -i '1i#include <stdlib.h>\n#include <string.h>' untex.c
+    mkdir -p $out/bin $out/share/man/man1
+  '';
+
+  meta = with lib; {
+    description = "A utility which removes LaTeX commands from input";
+    homepage = "https://www.ctan.org/pkg/untex";
+    license = licenses.gpl1;
+    maintainers = with maintainers; [ joachifm ];
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/uwc/default.nix b/pkgs/tools/text/uwc/default.nix
new file mode 100644
index 00000000000..14fe74723a3
--- /dev/null
+++ b/pkgs/tools/text/uwc/default.nix
@@ -0,0 +1,24 @@
+{ rustPlatform, lib, fetchFromGitLab }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "uwc";
+  version = "1.0.4";
+
+  src = fetchFromGitLab {
+    owner = "dead10ck";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "1ywqq9hrrm3frvd2sswknxygjlxi195kcy7g7phwq63j7hkyrn50";
+  };
+
+  cargoSha256 = "04pslga3ff766cpb73n6ivzmqfa0hm19gcla8iyv6p59ddsajh3q";
+
+  doCheck = true;
+
+  meta = with lib; {
+    description = "Like wc, but unicode-aware, and with per-line mode";
+    homepage = "https://gitlab.com/dead10ck/uwc";
+    license = licenses.mit;
+    maintainers = with maintainers; [ ShamrockLee ];
+  };
+}
diff --git a/pkgs/tools/text/vale/default.nix b/pkgs/tools/text/vale/default.nix
new file mode 100644
index 00000000000..9ecd7f44cfa
--- /dev/null
+++ b/pkgs/tools/text/vale/default.nix
@@ -0,0 +1,32 @@
+{ lib, buildGoModule, fetchFromGitHub }:
+
+buildGoModule rec {
+  pname = "vale";
+  version = "2.15.3";
+
+  subPackages = [ "cmd/vale" ];
+  outputs = [ "out" "data" ];
+
+  src = fetchFromGitHub {
+    owner = "errata-ai";
+    repo = "vale";
+    rev = "v${version}";
+    sha256 = "sha256-vhsn72xCe1wC4YRdo2m49iUj/3nVl0cyfeSmWRfESaY=";
+  };
+
+  vendorSha256 = "sha256-/0H35PGFFPch4jDnQ/ggctyHZJ5W/C1PNlkT5zzvI3M=";
+
+  postInstall = ''
+    mkdir -p $data/share/vale
+    cp -r styles $data/share/vale
+  '';
+
+  ldflags = [ "-s" "-w" "-X main.version=${version}" ];
+
+  meta = with lib; {
+    homepage = "https://docs.errata.ai/vale/about";
+    description = "A syntax-aware linter for prose built with speed and extensibility in mind";
+    license = licenses.mit;
+    maintainers = [ maintainers.marsam ];
+  };
+}
diff --git a/pkgs/tools/text/vgrep/default.nix b/pkgs/tools/text/vgrep/default.nix
new file mode 100644
index 00000000000..8da1917fdd0
--- /dev/null
+++ b/pkgs/tools/text/vgrep/default.nix
@@ -0,0 +1,32 @@
+{ lib, buildGoModule, fetchFromGitHub, go-md2man, installShellFiles }:
+
+buildGoModule rec {
+  pname = "vgrep";
+  version = "2.6.0";
+
+  src = fetchFromGitHub {
+    owner = "vrothberg";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-RLyEOvNhb1oXPYYxVZKc+xN2uCgUaWMxh8dPEOUfAFA=";
+  };
+
+  vendorSha256 = null;
+
+  ldflags = [ "-s" "-w" "-X main.version=${version}" ];
+
+  nativeBuildInputs = [ go-md2man installShellFiles ];
+
+  postBuild = ''
+    sed -i '/SHELL= /d' Makefile
+    make docs
+    installManPage docs/*.[1-9]
+  '';
+
+  meta = with lib; {
+    description = "User-friendly pager for grep/git-grep/ripgrep";
+    homepage = "https://github.com/vrothberg/vgrep";
+    license = licenses.gpl3Only;
+    maintainers = with maintainers; [ SuperSandro2000 ];
+  };
+}
diff --git a/pkgs/tools/text/wdiff/default.nix b/pkgs/tools/text/wdiff/default.nix
new file mode 100644
index 00000000000..510cf18369e
--- /dev/null
+++ b/pkgs/tools/text/wdiff/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchurl, texinfo, which }:
+
+stdenv.mkDerivation rec {
+  pname = "wdiff";
+  version = "1.2.2";
+
+  src = fetchurl {
+    url = "mirror://gnu/wdiff/${pname}-${version}.tar.gz";
+    sha256 = "0sxgg0ms5lhi4aqqvz1rj4s77yi9wymfm3l3gbjfd1qchy66kzrl";
+  };
+
+  # for makeinfo
+  nativeBuildInputs = [ texinfo ];
+
+  buildInputs = [ texinfo ];
+
+  checkInputs = [ which ];
+
+  strictDeps = true;
+
+  meta = with lib; {
+    homepage = "https://www.gnu.org/software/wdiff/";
+    description = "Comparing files on a word by word basis";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ eelco SuperSandro2000 ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/wgetpaste/default.nix b/pkgs/tools/text/wgetpaste/default.nix
new file mode 100644
index 00000000000..ce757401b36
--- /dev/null
+++ b/pkgs/tools/text/wgetpaste/default.nix
@@ -0,0 +1,30 @@
+{ lib, stdenv, fetchurl, wget, bash }:
+
+stdenv.mkDerivation rec {
+  pname = "wgetpaste";
+  version = "2.32";
+
+  src = fetchurl {
+    url = "https://github.com/zlin/wgetpaste/releases/download/${version}/wgetpaste-${version}.tar.xz";
+    sha256 = "04yv1hndxhrc5axwiw1yy0yrw1kli5fk4yj4267l7xdwqzxvl7b2";
+  };
+  # currently zsh-autocompletion support is not installed
+
+  prePatch = ''
+    substituteInPlace wgetpaste --replace "/usr/bin/env bash" "${bash}/bin/bash"
+    substituteInPlace wgetpaste --replace "LC_ALL=C wget" "LC_ALL=C ${wget}/bin/wget"
+  '';
+
+  installPhase = ''
+    mkdir -p $out/bin;
+    cp wgetpaste $out/bin;
+  '';
+
+  meta = {
+    description = "Command-line interface to various pastebins";
+    homepage = "https://github.com/zlin/wgetpaste";
+    license = lib.licenses.publicDomain;
+    maintainers = with lib.maintainers; [ qknight domenkozar ];
+    platforms = lib.platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/wrap/default.nix b/pkgs/tools/text/wrap/default.nix
new file mode 100644
index 00000000000..e228f946a8c
--- /dev/null
+++ b/pkgs/tools/text/wrap/default.nix
@@ -0,0 +1,36 @@
+{ lib, buildGoModule, fetchFromGitHub, fetchpatch, makeWrapper, courier-prime }:
+
+buildGoModule rec {
+  pname = "wrap";
+  version = "0.3.1";
+
+  src = fetchFromGitHub {
+    owner = "Wraparound";
+    repo = "wrap";
+    rev = "v${version}";
+    sha256 = "0scf7v83p40r9k7k5v41rwiy9yyanfv3jm6jxs9bspxpywgjrk77";
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  vendorSha256 = "03q5a5lm8zj1523gxkbc0y6a3mjj1z2h7nrr2qcz8nlghvp4cfaz";
+
+  patches = [
+    (fetchpatch {
+      name = "courier-prime-variants.patch";
+      url = "https://github.com/Wraparound/wrap/commit/b72c280b6eddba9ec7b3507c1f143eb28a85c9c1.patch";
+      sha256 = "1d9v0agfd7mgd17k4a8l6vr2kyswyfsyq3933dz56pgs5d3jric5";
+    })
+  ];
+
+  postInstall = ''
+    wrapProgram $out/bin/wrap --prefix XDG_DATA_DIRS : ${courier-prime}/share/
+  '';
+
+  meta = with lib; {
+    description = "A Fountain export tool with some extras";
+    homepage = "https://github.com/Wraparound/wrap";
+    license = licenses.gpl3Only;
+    maintainers = [ maintainers.austinbutler ];
+  };
+}
diff --git a/pkgs/tools/text/xidel/default.nix b/pkgs/tools/text/xidel/default.nix
new file mode 100644
index 00000000000..97c74e37008
--- /dev/null
+++ b/pkgs/tools/text/xidel/default.nix
@@ -0,0 +1,93 @@
+{ lib, stdenv, fetchsvn, fetchFromGitHub, fpc }:
+
+let
+  flreSrc = fetchFromGitHub {
+    owner = "benibela";
+    repo = "flre";
+    rev = "5aa8a9e032feff7a5790104f2d53fa74c70bb1d9"; # latest as of 0.9.8 release date
+    sha256 = "1zny494jm92fjgfirzwmxff988j4yygblaxmaclkkmcvzkjrzs05";
+  };
+  synapseSrc = fetchsvn {
+    url = "http://svn.code.sf.net/p/synalist/code/synapse/40/";
+    rev = 237;
+    sha256 = "0ciqd2xgpinwrk42cpyinh9gz2i5s5rlww4mdlsca1h6saivji96";
+  };
+  rcmdlineSrc = fetchFromGitHub {
+    owner = "benibela";
+    repo = "rcmdline";
+    rev = "96859e574e82d76eae49d5552a8c5aa7574a5987"; # latest as of 0.9.8 release date
+    sha256 = "0vwvpwrxsy9axicbck143yfxxrdifc026pv9c2lzqxzskf9fd78b";
+  };
+  internettoolsSrc = fetchFromGitHub {
+    owner = "benibela";
+    repo = "internettools";
+    rev = "c9c5cc3a87271180d4fb5bb0b17040763d2cfe06"; # latest as of 0.9.8 release date
+    sha256 = "057hn7cb1vy827gvim3b6vwgfdh2ckjy8h9yj1ry7lv6hw8ynx6n";
+  };
+in stdenv.mkDerivation rec {
+  pname = "xidel";
+  version = "0.9.8";
+
+  src = fetchFromGitHub {
+    owner = "benibela";
+    repo = pname;
+    rev = "Xidel_${version}";
+    sha256 = "0q75jjyciybvj6y17s2283zis9fcw8w5pfsq8bn7diinnbjnzgl6";
+  };
+
+  nativeBuildInputs = [ fpc ];
+
+  patchPhase = ''
+    patchShebangs \
+      build.sh \
+      tests/test.sh \
+      tests/tests-file-module.sh \
+      tests/tests.sh \
+      tests/downloadTest.sh \
+      tests/downloadTests.sh \
+      tests/zorbajsoniq.sh \
+      tests/zorbajsoniq/download.sh
+  '';
+
+  preBuildPhase = ''
+    mkdir -p import/{flre,synapse} rcmdline internettools
+    cp -R ${flreSrc}/. import/flre
+    cp -R ${synapseSrc}/. import/synapse
+    cp -R ${rcmdlineSrc}/. rcmdline
+    cp -R ${internettoolsSrc}/. internettools
+  '';
+
+  buildPhase = ''
+    runHook preBuildPhase
+    ./build.sh
+    runHook postBuildPhase
+  '';
+
+  installPhase = ''
+    mkdir -p "$out/bin" "$out/share/man/man1"
+    cp meta/xidel.1 "$out/share/man/man1/"
+    cp xidel "$out/bin/"
+  '';
+
+  doCheck = true;
+
+  checkPhase = ''
+    # Not all, if any, of these tests are blockers. Failing or not this phase will pass.
+    # As of 2021-08-15, all of 37 failed tests are linked with the lack of network access.
+    ./tests/tests.sh
+  '';
+
+  doInstallCheck = true;
+
+  installCheckPhase = ''
+    $out/bin/xidel --version | grep "${version}"
+  '';
+
+  meta = with lib; {
+    description = "Command line tool to download and extract data from HTML/XML pages as well as JSON APIs";
+    homepage = "https://www.videlibri.de/xidel.html";
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+    maintainers = [ maintainers.bjornfor ];
+  };
+}
diff --git a/pkgs/tools/text/xml/basex/basex.svg b/pkgs/tools/text/xml/basex/basex.svg
new file mode 100644
index 00000000000..9d476cec2ca
--- /dev/null
+++ b/pkgs/tools/text/xml/basex/basex.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2178"
+   sodipodi:version="0.32"
+   inkscape:version="0.45"
+   width="1568"
+   height="1164"
+   version="1.0"
+   sodipodi:docbase="F:\Uni\Scholl\Research\Conferences\BTW2007\Poster"
+   sodipodi:docname="Logo.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:modified="true">
+  <metadata
+     id="metadata2183">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs2181" />
+  <sodipodi:namedview
+     inkscape:window-height="1150"
+     inkscape:window-width="1143"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     guidetolerance="10.0"
+     gridtolerance="10.0"
+     objecttolerance="10.0"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     inkscape:zoom="0.64948454"
+     inkscape:cx="784"
+     inkscape:cy="584.00852"
+     inkscape:window-x="412"
+     inkscape:window-y="20"
+     inkscape:current-layer="layer2"
+     showgrid="false"
+     inkscape:object-bbox="true"
+     inkscape:object-points="true"
+     gridempspacing="10" />
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     style="opacity:1">
+    <path
+       style="font-size:1470px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:19.98425102;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;font-family:Clarendo"
+       d="M 628.08008,847.55762 C 613.24569,864.30587 601.88095,879.3791 593.98584,892.77734 C 586.08995,906.17595 582.1422,916.94254 582.14258,925.07715 C 582.1422,937.9972 586.92735,947.08899 596.49805,952.35254 C 606.06796,957.61633 624.49079,960.24816 651.7666,960.24805 L 720.67285,960.24805 L 720.67285,1072.2207 L 207.46484,1072.2207 L 207.46484,960.24805 L 256.27344,960.24805 C 284.9843,960.24816 308.07265,955.94152 325.53857,947.32813 C 343.00426,938.71498 364.89633,919.09586 391.21484,888.4707 L 673.2998,568.34375 L 441.45898,276.92773 C 416.57596,245.82505 393.60723,224.77038 372.55273,213.76367 C 351.4979,202.75868 325.89734,197.25576 295.75098,197.25488 L 245.50684,197.25488 L 245.50684,86 L 767.32813,86 L 767.32813,197.25488 L 699.85742,197.25488 C 685.97999,197.25576 675.45266,199.76796 668.27539,204.7915 C 661.0972,209.81678 657.50834,217.11414 657.50879,226.68359 C 657.50834,233.38365 659.30277,240.20249 662.89209,247.14014 C 666.4805,254.07943 672.58156,262.57308 681.19531,272.62109 L 810.39453,429.81348 L 967.58691,265.44336 C 974.76388,258.26644 980.50606,250.84945 984.81348,243.19238 C 989.11933,235.53697 991.27265,229.07702 991.27344,223.8125 C 991.27265,215.20008 985.88936,208.62049 975.12354,204.07373 C 964.35618,199.5287 948.20629,197.25576 926.67383,197.25488 L 869.25195,197.25488 L 869.25195,86 L 1332.2158,86 L 1332.2158,197.25488 L 1279.1006,197.25488 C 1241.2968,197.25576 1189.8564,233.14439 1124.7793,304.9209 L 1123.3438,306.35645 L 905.8584,544.65723 L 1155.6436,856.1709 C 1194.8808,904.97966 1224.6684,934.52797 1245.0063,944.81592 C 1265.3422,955.10412 1294.412,960.24816 1332.2158,960.24805 L 1376,960.24805 L 1376,1072.2207 L 810.39453,1072.2207 L 810.39453,960.24805 L 877.86523,960.24805 C 901.79032,960.24816 919.25612,958.21447 930.2627,954.14697 C 941.26782,950.07971 946.77074,943.26087 946.77148,933.69043 C 946.77074,926.51284 945.3352,918.97623 942.46484,911.08057 C 939.59302,903.18523 935.28638,895.64861 929.54492,888.4707 L 768.76367,685.34082 L 628.08008,847.55762 z "
+       id="text2175" />
+    <path
+       style="font-size:500px;font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#e00000;fill-opacity:1;stroke:#ffffff;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;font-family:Arial Black"
+       d="M 146.16714,395.52869 L 353.19839,395.52869 C 387.70332,395.52904 414.19255,404.07396 432.66616,421.16345 C 451.13913,438.25361 460.37577,459.41244 460.37612,484.64001 C 460.37577,505.79912 453.78398,523.94688 440.60073,539.08337 C 431.81135,549.17472 418.95329,557.14998 402.02651,563.00916 C 427.74234,569.19424 446.66322,579.81434 458.78921,594.86951 C 470.9145,609.92499 476.97732,628.84587 476.97768,651.6322 C 476.97732,670.18697 472.66417,686.8699 464.03823,701.68103 C 455.41158,716.49227 443.61146,728.211 428.63784,736.83728 C 419.36019,742.20839 405.3628,746.11463 386.64565,748.55603 C 361.74306,751.81124 345.22289,753.43884 337.08511,753.43884 L 146.16714,753.43884 L 146.16714,395.52869 z M 257.7394,535.90955 L 305.83511,535.90955 C 323.0875,535.90976 335.09107,532.93939 341.84585,526.99841 C 348.60017,521.05789 351.97744,512.47229 351.97768,501.24158 C 351.97744,490.82517 348.60017,482.68716 341.84585,476.82751 C 335.09107,470.96842 323.33164,468.03874 306.56753,468.03845 L 257.7394,468.03845 L 257.7394,535.90955 z M 257.7394,676.53455 L 314.13589,676.53455 C 333.17863,676.53462 346.60635,673.15735 354.41909,666.40271 C 362.23134,659.64825 366.13758,650.57436 366.13784,639.18103 C 366.13758,628.60173 362.27203,620.0975 354.54116,613.66833 C 346.8098,607.23944 333.26001,604.02493 313.89175,604.02478 L 257.7394,604.02478 L 257.7394,676.53455 z "
+       id="text2205" />
+    <path
+       style="font-size:500px;font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#e00000;fill-opacity:1;stroke:#ffffff;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;font-family:Arial Black"
+       d="M 703.69272,694.35681 L 577.71616,694.35681 L 560.38217,753.43884 L 447.34506,753.43884 L 581.86655,395.52869 L 702.47202,395.52869 L 836.9935,753.43884 L 721.27084,753.43884 L 703.69272,694.35681 z M 680.49936,616.96423 L 640.94858,488.30212 L 601.64194,616.96423 L 680.49936,616.96423 z "
+       id="text3180" />
+    <path
+       style="font-size:500px;font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#e00000;fill-opacity:1;stroke:#ffffff;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;font-family:Arial Black"
+       d="M 810.90509,641.13416 L 916.1297,634.54236 C 918.40822,651.63231 923.04689,664.65313 930.04572,673.60486 C 941.4388,688.09061 957.71482,695.33344 978.87384,695.33337 C 994.6614,695.33344 1006.8277,691.63064 1015.3729,684.22498 C 1023.9176,676.81946 1028.19,668.23386 1028.1902,658.46814 C 1028.19,649.19091 1024.121,640.89013 1015.9832,633.5658 C 1007.845,626.24171 988.96479,619.3244 959.34259,612.81384 C 910.83987,601.90905 876.25331,587.42339 855.58282,569.35681 C 834.74945,551.29061 824.33279,528.26004 824.33282,500.26501 C 824.33279,481.87337 829.66319,464.49871 840.32404,448.14099 C 850.98479,431.7839 867.01667,418.92584 888.41974,409.56677 C 909.82262,400.20841 939.16015,395.52905 976.43243,395.52869 C 1022.1679,395.52905 1057.0393,404.03327 1081.0467,421.04138 C 1105.0535,438.05017 1119.3358,465.10906 1123.8934,502.21814 L 1019.6453,508.32166 C 1016.8782,492.20864 1011.0595,480.4899 1002.1893,473.16541 C 993.31863,465.84148 981.07092,462.17937 965.44611,462.17908 C 952.58787,462.17937 942.90364,464.90561 936.39337,470.35779 C 929.88282,475.81055 926.62761,482.44303 926.62775,490.25525 C 926.62761,495.95213 929.31316,501.07908 934.68439,505.63611 C 939.89257,510.35641 952.26235,514.75094 971.79376,518.8197 C 1020.1334,529.2366 1054.7606,539.77533 1075.6756,550.43591 C 1096.59,561.09692 1111.8081,574.32119 1121.3299,590.10876 C 1130.851,605.89668 1135.6118,623.55617 1135.6121,643.08728 C 1135.6118,666.03659 1129.2641,687.19543 1116.5692,706.56384 C 1103.8735,725.93237 1086.1327,740.62148 1063.3465,750.63123 C 1040.5598,760.64099 1011.8326,765.64587 977.16486,765.64587 C 916.29234,765.64587 874.13743,753.92713 850.70001,730.48962 C 827.26248,707.05218 813.99752,677.26705 810.90509,641.13416 L 810.90509,641.13416 z "
+       id="text3184" />
+    <path
+       style="font-size:500px;font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#e00000;fill-opacity:1;stroke:#ffffff;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;font-family:Arial Black"
+       d="M 1139.0592,395.52869 L 1435.4459,395.52869 L 1435.4459,471.9447 L 1249.899,471.9447 L 1249.899,528.82947 L 1422.0182,528.82947 L 1422.0182,601.82751 L 1249.899,601.82751 L 1249.899,672.38416 L 1440.817,672.38416 L 1440.817,753.43884 L 1139.0592,753.43884 L 1139.0592,395.52869 z "
+       id="text3188" />
+  </g>
+</svg>
diff --git a/pkgs/tools/text/xml/basex/default.nix b/pkgs/tools/text/xml/basex/default.nix
new file mode 100644
index 00000000000..4d6d23054da
--- /dev/null
+++ b/pkgs/tools/text/xml/basex/default.nix
@@ -0,0 +1,67 @@
+{ lib, stdenv, fetchurl, unzip, jre, coreutils, makeDesktopItem, copyDesktopItems }:
+
+stdenv.mkDerivation rec {
+  pname = "basex";
+  version = "9.6.3";
+
+  src = fetchurl {
+    url = "http://files.basex.org/releases/${version}/BaseX${builtins.replaceStrings ["."] [""] version}.zip";
+    hash = "sha256-OlIAyGUQKrl+Zu79p6cahHpx59zLozGkUDAEvykGN6Y=";
+  };
+
+  nativeBuildInputs = [ unzip copyDesktopItems ];
+  buildInputs = [ jre ];
+
+  desktopItems = lib.optional (!stdenv.isDarwin) (makeDesktopItem {
+    name = "basex";
+    exec = "basexgui %f";
+    icon = "${./basex.svg}"; # icon copied from Ubuntu basex package
+    comment = "Visually query and analyse your XML data";
+    desktopName = "BaseX XML Database";
+    genericName = "XML database tool";
+    categories = [ "Development" "Utility" "Database" ];
+    mimeTypes = [ "text/xml" ];
+  });
+
+  dontBuild = true;
+
+  installPhase = ''
+    runHook preInstall
+
+    # Remove Windows batch files (unclutter $out/bin)
+    rm ./bin/*.bat
+
+    mkdir -p "$out/share/basex"
+
+    cp -R bin etc lib webapp src BaseX.jar "$out"
+    cp -R readme.txt webapp "$out/share/basex"
+
+    # Use substitutions instead of wrapper scripts
+    for file in "$out"/bin/*; do
+        sed -i -e "s|/usr/bin/env bash|${stdenv.shell}|" \
+               -e "s|java|${jre}/bin/java|" \
+               -e "s|readlink|${coreutils}/bin/readlink|" \
+               -e "s|dirname|${coreutils}/bin/dirname|" \
+               -e "s|basename|${coreutils}/bin/basename|" \
+               -e "s|echo|${coreutils}/bin/echo|" \
+            "$file"
+    done
+
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "XML database and XPath/XQuery processor";
+    longDescription = ''
+      BaseX is a very fast and light-weight, yet powerful XML database and
+      XPath/XQuery processor, including support for the latest W3C Full Text
+      and Update Recommendations. It supports large XML instances and offers a
+      highly interactive front-end (basexgui). Apart from two local standalone
+      modes, BaseX offers a client/server architecture.
+    '';
+    homepage = "https://basex.org/";
+    license = licenses.bsd3;
+    platforms = platforms.unix;
+    maintainers = [ maintainers.bjornfor ];
+  };
+}
diff --git a/pkgs/tools/text/xml/html-xml-utils/default.nix b/pkgs/tools/text/xml/html-xml-utils/default.nix
new file mode 100644
index 00000000000..f1ab390e481
--- /dev/null
+++ b/pkgs/tools/text/xml/html-xml-utils/default.nix
@@ -0,0 +1,20 @@
+{ lib, stdenv, fetchurl, curl, libiconv }:
+
+stdenv.mkDerivation rec {
+  pname = "html-xml-utils";
+  version = "8.3";
+
+  src = fetchurl {
+    url = "https://www.w3.org/Tools/HTML-XML-utils/${pname}-${version}.tar.gz";
+    sha256 = "sha256-pQxNFtrWYK1nku9TvHfvqdVyl5diN3Gj/OUtjiPT0Iw=";
+  };
+
+  buildInputs = [curl libiconv];
+
+  meta = with lib; {
+    description = "Utilities for manipulating HTML and XML files";
+    homepage = "http://www.w3.org/Tools/HTML-XML-utils/";
+    license = licenses.w3c;
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/xml/jing-trang/default.nix b/pkgs/tools/text/xml/jing-trang/default.nix
new file mode 100644
index 00000000000..02f745575ad
--- /dev/null
+++ b/pkgs/tools/text/xml/jing-trang/default.nix
@@ -0,0 +1,51 @@
+{ lib, stdenv, fetchFromGitHub, jre_headless, jdk, ant, saxon }:
+
+stdenv.mkDerivation rec {
+  pname = "jing-trang";
+  version = "20181222";
+
+  src = fetchFromGitHub {
+    owner = "relaxng";
+    repo = "jing-trang";
+    rev = "V${version}";
+    sha256 = "sha256-Krupa3MGk5UaaQsaNpPMZuIUzHJytDiksz9ysCPkFS4=";
+    fetchSubmodules = true;
+  };
+
+  buildInputs = [ jdk ant saxon ];
+
+  CLASSPATH = "lib/saxon.jar";
+
+  patches = [
+    ./no-git-during-build.patch
+  ];
+
+  preBuild = "ant";
+
+  installPhase = ''
+    mkdir -p "$out"/{share/java,bin}
+    cp ./build/*.jar "$out/share/java/"
+
+    for tool in jing trang; do
+    cat > "$out/bin/$tool" <<EOF
+    #! $SHELL
+    export JAVA_HOME='${jre_headless}'
+    exec '${jre_headless}/bin/java' -jar '$out/share/java/$tool.jar' "\$@"
+    EOF
+    done
+
+    chmod +x "$out"/bin/*
+  '';
+
+  doCheck = true;
+  checkPhase = "ant test";
+
+  meta = with lib; {
+    description = "A RELAX NG validator in Java";
+    # The homepage is www.thaiopensource.com, but it links to googlecode.com
+    # for downloads and call it the "project site".
+    homepage = "https://www.thaiopensource.com/relaxng/trang.html";
+    platforms = platforms.unix;
+    maintainers = [ maintainers.bjornfor ];
+  };
+}
diff --git a/pkgs/tools/text/xml/jing-trang/no-git-during-build.patch b/pkgs/tools/text/xml/jing-trang/no-git-during-build.patch
new file mode 100644
index 00000000000..3fc9b3f6ef5
--- /dev/null
+++ b/pkgs/tools/text/xml/jing-trang/no-git-during-build.patch
@@ -0,0 +1,47 @@
+From db0ed6267f1a85f0785c81b8ee396f74795c77c0 Mon Sep 17 00:00:00 2001
+From: Thomas Gerbet <thomas@gerbet.me>
+Date: Sat, 27 Nov 2021 10:24:07 +0100
+Subject: [PATCH] Do not rely on Git during the build
+
+---
+ build.xml | 6 ------
+ build.xsl | 6 ------
+ 2 files changed, 12 deletions(-)
+
+diff --git a/build.xml b/build.xml
+index e8ebaed8..2d26c72f 100644
+--- a/build.xml
++++ b/build.xml
+@@ -431,12 +431,6 @@
+ <target name="clean" 
+ 	description="Remove almost all files created during the build process">
+   <delete dir="${build.dir}"/>
+-  <exec executable="git">
+-    <arg value="clean"/>
+-    <arg value="-d"/>
+-    <arg value="--force"/>
+-    <arg value="${doc.dir}"/>
+-  </exec>
+ </target>
+ 
+ <target name="realclean" depends="clean"
+diff --git a/build.xsl b/build.xsl
+index fb9f3fef..fa384a27 100644
+--- a/build.xsl
++++ b/build.xsl
+@@ -23,12 +23,6 @@
+     <target name="dummy"/>
+     <target name="init">
+       <mkdir dir="{$build}"/>
+-      <exec executable="git">
+-        <arg value="submodule"/>
+-        <arg value="update"/>
+-        <arg value="--init"/>
+-        <arg value="--recursive"/>
+-      </exec>
+       <copy todir="{$doc}">
+         <fileset dir="relaxng.org/jclark" includes="**"/>
+       </copy>
+-- 
+2.34.1
+
diff --git a/pkgs/tools/text/xml/rnv/default.nix b/pkgs/tools/text/xml/rnv/default.nix
new file mode 100644
index 00000000000..1ee3355d105
--- /dev/null
+++ b/pkgs/tools/text/xml/rnv/default.nix
@@ -0,0 +1,20 @@
+{ lib, stdenv, fetchurl, expat }:
+
+stdenv.mkDerivation rec {
+  pname = "rnv";
+  version = "1.7.11";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/rnv/rnv-${version}.tar.xz";
+    sha256 = "1rlxrkkkp8b5j6lyvnd9z1d85grmwwmdggkxq6yl226nwkqj1faa";
+  };
+
+  buildInputs = [ expat ];
+
+  meta = with lib; {
+    description = "Relax NG Compact Syntax validator";
+    homepage = "http://www.davidashen.net/rnv.html";
+    license = licenses.bsd3;
+    platforms = platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/xml/rxp/default.nix b/pkgs/tools/text/xml/rxp/default.nix
new file mode 100644
index 00000000000..918a491ede3
--- /dev/null
+++ b/pkgs/tools/text/xml/rxp/default.nix
@@ -0,0 +1,18 @@
+{lib, stdenv, fetchurl} :
+
+stdenv.mkDerivation rec {
+  pname = "rxp";
+  version = "1.5.0";
+
+  src = fetchurl {
+    url = "mirror://debian/pool/main/r/rxp/rxp_${version}.orig.tar.gz";
+    sha256 = "0y365r36wzj4xn1dzhb03spxljnrx8vwqbiwnnwz4630129gzpm6";
+  };
+
+  meta = {
+    license = lib.licenses.gpl2Plus;
+    description = "A validating XML parser written in C";
+    homepage = "https://www.cogsci.ed.ac.uk/~richard/rxp.html";
+    platforms = lib.platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/xml/xml2/default.nix b/pkgs/tools/text/xml/xml2/default.nix
new file mode 100644
index 00000000000..265ab10e5ac
--- /dev/null
+++ b/pkgs/tools/text/xml/xml2/default.nix
@@ -0,0 +1,22 @@
+{ lib, stdenv, fetchurl, pkg-config, libxml2 }:
+
+stdenv.mkDerivation rec {
+  pname = "xml2";
+  version = "0.5";
+
+  src = fetchurl {
+    url = "https://web.archive.org/web/20160427221603/http://download.ofb.net/gale/xml2-${version}.tar.gz";
+    sha256 = "01cps980m99y99cnmvydihga9zh3pvdsqag2fi1n6k2x7rfkl873";
+  };
+
+  nativeBuildInputs = [ pkg-config ];
+  buildInputs = [ libxml2 ];
+
+  meta = with lib; {
+    homepage = "https://web.archive.org/web/20160515005047/http://dan.egnor.name:80/xml2";
+    description = "Tools for command line processing of XML, HTML, and CSV";
+    license = licenses.gpl2Plus;
+    platforms = platforms.all;
+    maintainers = [ maintainers.rycee ];
+  };
+}
diff --git a/pkgs/tools/text/xml/xmldiff/default.nix b/pkgs/tools/text/xml/xmldiff/default.nix
new file mode 100644
index 00000000000..5814435e111
--- /dev/null
+++ b/pkgs/tools/text/xml/xmldiff/default.nix
@@ -0,0 +1,41 @@
+{ lib
+, buildPythonApplication
+, fetchFromGitHub
+, lxml
+, six
+}:
+
+buildPythonApplication rec {
+  pname = "xmldiff";
+  version = "2.4";
+
+  src = fetchFromGitHub {
+    owner = "Shoobx";
+    repo = pname;
+    rev = version;
+    hash = "sha256-xqudHYfwOce2C0pcFzId0JDIIC6R5bllmVKsH+CvTdE=";
+  };
+
+  buildInputs = [
+    lxml
+    six
+  ];
+
+  meta = with lib; {
+    homepage = "https://xmldiff.readthedocs.io/en/stable/";
+    description = "A library and command line utility for diffing xml";
+    longDescription = ''
+      xmldiff is a library and a command-line utility for making diffs out of
+      XML. This may seem like something that doesn't need a dedicated utility,
+      but change detection in hierarchical data is very different from change
+      detection in flat data. XML type formats are also not only used for
+      computer readable data, it is also often used as a format for hierarchical
+      data that can be rendered into human readable formats. A traditional diff
+      on such a format would tell you line by line the differences, but this
+      would not be be readable by a human. xmldiff provides tools to make human
+      readable diffs in those situations.
+    '';
+    license = licenses.mit;
+    maintainers = with maintainers; [ AndersonTorres ];
+  };
+}
diff --git a/pkgs/tools/text/xml/xmlformat/default.nix b/pkgs/tools/text/xml/xmlformat/default.nix
new file mode 100644
index 00000000000..380baa906c2
--- /dev/null
+++ b/pkgs/tools/text/xml/xmlformat/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchurl, perl }:
+stdenv.mkDerivation rec {
+  pname = "xmlformat";
+  version = "1.04";
+
+  src = fetchurl {
+    url = "http://www.kitebird.com/software/xmlformat/xmlformat-${version}.tar.gz";
+    sha256 = "1vwgzn4ha0az7dx0cyc6dx5nywwrx9gxhyh08mvdcq27wjbh79vi";
+  };
+
+  buildInputs = [ perl ];
+  buildPhase = ''
+    patchShebangs ./xmlformat.pl
+  '';
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp ./xmlformat.pl $out/bin/xmlformat
+    cp ./LICENSE $out/
+  '';
+
+  meta = {
+    description = "a configurable formatter (or 'pretty-printer') for XML documents";
+    homepage = "http://www.kitebird.com/software/xmlformat/";
+    license = lib.licenses.bsd3;
+    platforms = lib.platforms.all;
+  };
+}
diff --git a/pkgs/tools/text/xml/xmloscopy/default.nix b/pkgs/tools/text/xml/xmloscopy/default.nix
new file mode 100644
index 00000000000..c915e2c7fc5
--- /dev/null
+++ b/pkgs/tools/text/xml/xmloscopy/default.nix
@@ -0,0 +1,53 @@
+{ stdenv, lib, makeWrapper, dev_only_shellcheck ? null,
+fetchFromGitHub,
+
+fzf, coreutils, libxml2, libxslt, jing, findutils, gnugrep, gnused,
+docbook5
+}:
+stdenv.mkDerivation rec {
+  pname = "xmloscopy";
+  version = "0.1.3";
+
+  nativeBuildInputs = [
+    makeWrapper
+    dev_only_shellcheck
+  ];
+
+  spath = lib.makeBinPath [
+    fzf
+    coreutils
+    libxml2
+    libxslt
+    jing
+    findutils
+    gnugrep
+    gnused
+  ];
+
+  src = fetchFromGitHub {
+    owner = "grahamc";
+    repo = "xmloscopy";
+    rev = "v${version}";
+    sha256 = "06y5bckrmnq7b5ny2hfvlmdws910jw3xbw5nzy3bcpqsccqnjxrc";
+  };
+
+  installPhase = ''
+    sed -i "s/hard to say/v${version}/" ./xmloscopy
+    type -P shellcheck && shellcheck ./xmloscopy
+    chmod +x ./xmloscopy
+    patchShebangs ./xmloscopy
+    mkdir -p $out/bin
+    cp ./xmloscopy $out/bin/
+    wrapProgram $out/bin/xmloscopy \
+      --set RNG "${docbook5}/xml/rng/docbook/docbook.rng" \
+      --set PATH "${spath}"
+  '';
+
+  meta = with lib; {
+    description = "wtf is my docbook broken?";
+    homepage = "https://github.com/grahamc/xmloscopy";
+    license = licenses.mit;
+    platforms = platforms.all;
+    maintainers = with maintainers; [ grahamc ];
+  };
+}
diff --git a/pkgs/tools/text/xml/xmlstarlet/default.nix b/pkgs/tools/text/xml/xmlstarlet/default.nix
new file mode 100644
index 00000000000..39d53088bab
--- /dev/null
+++ b/pkgs/tools/text/xml/xmlstarlet/default.nix
@@ -0,0 +1,34 @@
+{ lib, stdenv, fetchurl, pkg-config, libxml2, libxslt }:
+
+stdenv.mkDerivation rec {
+  pname = "xmlstarlet";
+  version = "1.6.1";
+
+  src = fetchurl {
+    url = "mirror://sourceforge/xmlstar/xmlstarlet-${version}.tar.gz";
+    sha256 = "1jp737nvfcf6wyb54fla868yrr39kcbijijmjpyk4lrpyg23in0m";
+  };
+
+  nativeBuildInputs = [ pkg-config ];
+  buildInputs = [ libxml2 libxslt ];
+
+  preConfigure =
+    ''
+      export LIBXSLT_PREFIX=${libxslt.dev}
+      export LIBXML_PREFIX=${libxml2.dev}
+      export LIBXSLT_LIBS=$(pkg-config --libs libxslt libexslt)
+      export LIBXML_LIBS=$(pkg-config --libs libxml-2.0)
+    '';
+
+  postInstall =
+    ''
+      ln -s xml $out/bin/xmlstarlet
+    '';
+
+  meta = {
+    description = "A command line tool for manipulating and querying XML data";
+    homepage = "http://xmlstar.sourceforge.net/";
+    license = lib.licenses.mit;
+    platforms = lib.platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/xml/xpf/default.nix b/pkgs/tools/text/xml/xpf/default.nix
new file mode 100644
index 00000000000..ce0813c2ef4
--- /dev/null
+++ b/pkgs/tools/text/xml/xpf/default.nix
@@ -0,0 +1,21 @@
+{lib, stdenv, fetchurl, python2, libxml2}:
+
+assert libxml2.pythonSupport == true;
+
+stdenv.mkDerivation rec {
+  pname = "xpf";
+  version = "0.2";
+
+  src = fetchurl {
+    url = "http://tarballs.nixos.org/xpf-${version}.tar.gz";
+    sha256 = "0ljx91w68rnh4871c0xlq2whlmhqz8dr39wcdczfjjpniqz1fmpz";
+  };
+
+  buildInputs = [ python2 libxml2 ];
+
+  meta = {
+    description = "XML Pipes and Filters - command line tools for manipulating and querying XML data";
+    homepage = "http://www.cs.uu.nl/wiki/bin/view/Martin/XmlPipesAndFilters";
+    platforms = lib.platforms.unix;
+  };
+}
diff --git a/pkgs/tools/text/xsv/default.nix b/pkgs/tools/text/xsv/default.nix
new file mode 100644
index 00000000000..303b38d65c2
--- /dev/null
+++ b/pkgs/tools/text/xsv/default.nix
@@ -0,0 +1,24 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, Security }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "xsv";
+  version = "0.13.0";
+
+  src = fetchFromGitHub {
+    owner = "BurntSushi";
+    repo = "xsv";
+    rev = version;
+    sha256 = "17v1nw36mrarrd5yv4xd3mpc1d7lvhd5786mqkzyyraf78pjg045";
+  };
+
+  cargoSha256 = "1bh60zgflaa5n914irkr4bpq3m4h2ngcj6bp5xx1qj112dwgvmyb";
+
+  buildInputs = lib.optional stdenv.isDarwin Security;
+
+  meta = with lib; {
+    description = "A fast CSV toolkit written in Rust";
+    homepage = "https://github.com/BurntSushi/xsv";
+    license = with licenses; [ unlicense /* or */ mit ];
+    maintainers = [ maintainers.jgertm ];
+  };
+}
diff --git a/pkgs/tools/text/xurls/default.nix b/pkgs/tools/text/xurls/default.nix
new file mode 100644
index 00000000000..774626561c9
--- /dev/null
+++ b/pkgs/tools/text/xurls/default.nix
@@ -0,0 +1,24 @@
+{ buildGoPackage, lib, fetchFromGitHub }:
+
+buildGoPackage rec {
+  version = "2.3.0";
+  pname = "xurls";
+
+  src = fetchFromGitHub {
+    owner = "mvdan";
+    repo = "xurls";
+    rev = "v${version}";
+    sha256 = "sha256-+oWYW7ZigkNS6VADNmVwarIsYyd730RAdDwnNIAYvlA=";
+  };
+
+  goPackagePath = "mvdan.cc/xurls/v2";
+  subPackages = [ "cmd/xurls" ];
+
+  meta = with lib; {
+    description = "Extract urls from text";
+    homepage = "https://github.com/mvdan/xurls";
+    maintainers = with maintainers; [ koral ];
+    platforms = platforms.unix;
+    license = licenses.bsd3;
+  };
+}
diff --git a/pkgs/tools/text/yaml-merge/default.nix b/pkgs/tools/text/yaml-merge/default.nix
new file mode 100644
index 00000000000..85ea3cd360d
--- /dev/null
+++ b/pkgs/tools/text/yaml-merge/default.nix
@@ -0,0 +1,29 @@
+{ lib, stdenv, fetchFromGitHub, python3Packages }:
+
+stdenv.mkDerivation {
+  pname = "yaml-merge";
+  version = "unstable-2022-01-12";
+
+  src = fetchFromGitHub {
+    owner = "abbradar";
+    repo = "yaml-merge";
+    rev = "2f0174fe92fc283dd38063a3a14f7fe71db4d9ec";
+    sha256 = "sha256-S2eZw+FOZvOn0XupZDRNcolUPd4PhvU1ziu+kx2AwnY=";
+  };
+
+  pythonPath = with python3Packages; [ pyyaml ];
+  nativeBuildInputs = with python3Packages;  [ wrapPython ];
+
+  installPhase = ''
+    install -Dm755 yaml-merge.py $out/bin/yaml-merge
+    wrapPythonPrograms
+  '';
+
+  meta = with lib; {
+    description = "Merge YAML data files";
+    homepage = "https://github.com/abbradar/yaml-merge";
+    license = licenses.bsd2;
+    platforms = platforms.unix;
+    maintainers = with maintainers; [ abbradar ];
+  };
+}
diff --git a/pkgs/tools/text/zimwriterfs/default.nix b/pkgs/tools/text/zimwriterfs/default.nix
new file mode 100644
index 00000000000..9a7e495df2b
--- /dev/null
+++ b/pkgs/tools/text/zimwriterfs/default.nix
@@ -0,0 +1,43 @@
+{ lib, stdenv
+, fetchFromGitHub
+
+, autoconf
+, automake
+, libtool
+, pkg-config
+
+, file
+, icu
+, gumbo
+, xz
+, xapian
+, zimlib
+, zlib
+}:
+
+stdenv.mkDerivation rec {
+  pname = "zimwriterfs";
+  version = "1.0";
+
+  src = fetchFromGitHub {
+    owner = "wikimedia";
+    repo = "openzim";
+    rev = "${pname}-${version}";
+    sha256 = "1vkrrq929a8s3m5rri1lg0l2vd0mc9n2fsb2z1g88k4n4j2l6f19";
+  };
+
+  nativeBuildInputs = [ automake autoconf libtool pkg-config ];
+  buildInputs = [ file icu gumbo xz zimlib zlib xapian ];
+  setSourceRoot = ''
+    sourceRoot=$(echo */zimwriterfs)
+  '';
+  preConfigure = "./autogen.sh";
+
+  meta = {
+    description = "A console tool to create ZIM files";
+    homepage = "http://git.wikimedia.org/log/openzim";
+    maintainers = with lib.maintainers; [ robbinch ];
+    license = lib.licenses.gpl3;
+    platforms = with lib.platforms; [ linux ];
+  };
+}
diff --git a/pkgs/tools/text/zoekt/default.nix b/pkgs/tools/text/zoekt/default.nix
new file mode 100644
index 00000000000..cb270f69ad1
--- /dev/null
+++ b/pkgs/tools/text/zoekt/default.nix
@@ -0,0 +1,29 @@
+{ lib
+, buildGoModule
+, fetchFromGitHub
+, git
+}:
+buildGoModule {
+  pname = "zoekt";
+  version = "unstable-2021-03-17";
+
+  src = fetchFromGitHub {
+    owner = "google";
+    repo = "zoekt";
+    rev = "d92b3b80e582e735b2459413ee7d9dbbf294d629";
+    sha256 = "JdORh6bRdHsAYwsmdKY0OUavXfu3HsPQFkQjRBkcMBo=";
+  };
+
+  vendorSha256 = "d+Xvl6fleMO0frP9qr5tZgkzsnH5lPELwmEQEspD22M=";
+
+  checkInputs = [
+    git
+  ];
+
+  meta = with lib; {
+    description = "Fast trigram based code search";
+    homepage = "https://github.com/google/zoekt";
+    license = licenses.asl20;
+    maintainers = teams.determinatesystems.members;
+  };
+}
diff --git a/pkgs/tools/text/zstxtns-utils/default.nix b/pkgs/tools/text/zstxtns-utils/default.nix
new file mode 100644
index 00000000000..362f2fca84d
--- /dev/null
+++ b/pkgs/tools/text/zstxtns-utils/default.nix
@@ -0,0 +1,39 @@
+{ coreutils
+, fetchurl
+, gnugrep
+, lib
+, makeWrapper
+, moreutils
+, stdenvNoCC
+}:
+
+stdenvNoCC.mkDerivation rec {
+  pname = "zstxtns-utils";
+  version = "0.0.3";
+
+  src = fetchurl {
+    url = "https://ytrizja.de/distfiles/zstxtns-utils-${version}.tar.gz";
+    sha256 = "I/Gm7vHUr29NClYWQ1kwu8HrNZpdLXfE/nutTNoqcdU=";
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  installPhase = ''
+    runHook preInstall
+    install -D -t $out/bin zstxtns-merge zstxtns-unmerge
+    runHook postInstall
+  '';
+
+  postInstall = ''
+    wrapProgram $out/bin/zstxtns-merge --set PATH "${lib.makeBinPath [coreutils gnugrep moreutils]}"
+    wrapProgram $out/bin/zstxtns-unmerge --set PATH "${lib.makeBinPath [coreutils gnugrep]}"
+  '';
+
+  meta = with lib; {
+    description = "utilities to deal with text based name service databases";
+    homepage = "https://ytrizja.de/";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ zseri ];
+    platforms = platforms.all;
+  };
+}