diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index b964b557..e56bd8dd 100644
--- a/assets/javascripts/news.json
+++ b/assets/javascripts/news.json
@@ -1,4 +1,8 @@
[
+ [
+ "2024-08-20",
+ "New documentation: Linux man pages"
+ ],
[
"2024-07-28",
"New documentation: OpenGL"
diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index 727576c7..52e4e0f9 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -142,6 +142,13 @@ $GS = '/usr/local/opt/ghostscript/bin/gs'; # GhostScript
```
+## Man
+
+```sh
+wget --recursive --no-parent https://man7.org/linux/man-pages/
+mv man7.org/linux/man-pages/ docs/man/
+```
+
## NumPy
```sh
diff --git a/lib/docs/filters/man/clean_html.rb b/lib/docs/filters/man/clean_html.rb
new file mode 100644
index 00000000..b78b0425
--- /dev/null
+++ b/lib/docs/filters/man/clean_html.rb
@@ -0,0 +1,20 @@
+module Docs
+ class Man
+ class CleanHtmlFilter < Filter
+ def call
+ css('.page-top').remove
+ css('.nav-bar').remove
+ css('.nav-end').remove
+ css('.sec-table').remove
+ css('a[href="#top_of_page"]').remove
+ css('.end-man-text').remove
+ css('.start-footer').remove
+ css('.footer').remove
+ css('.end-footer').remove
+ css('.statcounter').remove
+ css('form[action="https://www.google.com/search"]').remove
+ doc
+ end
+ end
+ end
+end
diff --git a/lib/docs/filters/man/entries.rb b/lib/docs/filters/man/entries.rb
new file mode 100644
index 00000000..72448113
--- /dev/null
+++ b/lib/docs/filters/man/entries.rb
@@ -0,0 +1,32 @@
+module Docs
+ class Man
+ class EntriesFilter < Docs::EntriesFilter
+
+ @@TYPES = {}
+
+ def get_name
+ return slug.split('/').last.sub(/\.(\d[^.]*)\z/, ' (\1)') if slug.start_with?('man')
+ at_css('h1').content.sub(' — Linux manual page', '')
+ end
+
+ def get_type
+ build_types if slug == 'dir_by_project'
+ @@TYPES[slug] or 'Linux manual page'
+ end
+
+ def build_types
+ type0 = nil
+ css('*').each do |node|
+ if node.name == 'h2'
+ type0 = node.content
+ elsif node.name == 'a' and node['href'] and node['href'].start_with?('man') and type0
+ # name = node.content + node.next_sibling.content
+ slug0 = node['href'].remove(/\.html\z/)
+ @@TYPES[slug0] = type0
+ end
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/docs/scrapers/man.rb b/lib/docs/scrapers/man.rb
new file mode 100644
index 00000000..07ac40d2
--- /dev/null
+++ b/lib/docs/scrapers/man.rb
@@ -0,0 +1,16 @@
+module Docs
+ class Man < FileScraper
+ self.name = 'Linux man pages'
+ self.type = 'simple'
+ self.slug = 'man'
+ self.base_url = "https://man7.org/linux/man-pages/"
+ self.initial_paths = %w(dir_by_project.html)
+ self.links = {
+ home: 'https://man7.org/linux/man-pages/',
+ }
+ html_filters.push 'man/entries', 'man/clean_html'
+ options[:attribution] = <<-HTML
+ ...
+ HTML
+ end
+end
diff --git a/public/icons/docs/man/16.png b/public/icons/docs/man/16.png
new file mode 100644
index 00000000..c3cd192c
Binary files /dev/null and b/public/icons/docs/man/16.png differ
diff --git a/public/icons/docs/man/16@2x.png b/public/icons/docs/man/16@2x.png
new file mode 100644
index 00000000..f6be19b2
Binary files /dev/null and b/public/icons/docs/man/16@2x.png differ
diff --git a/public/icons/docs/man/SOURCE b/public/icons/docs/man/SOURCE
new file mode 100644
index 00000000..8d82d154
--- /dev/null
+++ b/public/icons/docs/man/SOURCE
@@ -0,0 +1,2 @@
+https://mirrors.edge.kernel.org/images/favicon.ico
+https://commons.wikimedia.org/wiki/File:Tux.svg CC0