module wiki_base
import template::macro
-import opts
import ini
# A Nitiwiki instance.
# Synchronize local output with the distant `WikiConfig::rsync_dir`.
fun sync do
var root = expand_path(config.root_dir, config.out_dir)
- sys.system "rsync -vr --delete {root}/ {config.rsync_dir}"
+ var rsync_dir = config.rsync_dir
+ if rsync_dir == "" then
+ message("Error: configure `wiki.rsync_dir` to use rsync.", 0)
+ return
+ end
+ sys.system "rsync -vr --delete -- {root.escape_to_sh}/ {rsync_dir.escape_to_sh}"
end
# Pull data from git repository.
fun fetch do
- sys.system "git pull {config.git_origin} {config.git_branch}"
+ sys.system "git pull {config.git_origin.escape_to_sh} {config.git_branch.escape_to_sh}"
end
# Analyze wiki files from `dir` to build wiki entries.
print "nitiWiki"
print "name: {config.wiki_name}"
print "config: {config.ini_file}"
- print "url: {config.root_url}"
print ""
if root_section.is_dirty then
print "There is modified files:"
var entry = entries[path]
if not entry.is_dirty then continue
var name = entry.name
- if entry.has_source then name = entry.src_path.to_s
+ if entry.has_source then name = entry.src_path.as(not null)
if entry.is_new then
print " + {name}"
else
fun need_render(src, target: String): Bool do
if force_render then return true
if not target.file_exists then return true
- return src.file_stat.mtime >= target.file_stat.mtime
+ return src.file_stat.as(not null).mtime >= target.file_stat.as(not null).mtime
end
# Create a new `WikiSection`.
path = path.simplify_path
if entries.has_key(path) then return entries[path].as(WikiSection)
var root = expand_path(config.root_dir, config.source_dir)
- var name = path.basename("")
+ var name = path.basename
var section = new WikiSection(self, name)
entries[path] = section
if path == root then return section
end
var file = expand_path(config.root_dir, config.templates_dir, name)
var tpl = new TemplateString.from_file(file)
- if tpl.has_macro("ROOT_URL") then
- tpl.replace("ROOT_URL", config.root_url)
- end
if tpl.has_macro("TITLE") then
tpl.replace("TITLE", config.wiki_name)
end
return tpl
end
+ # Does a sideblock named `name` exists for this wiki?
+ fun has_sideblock(name: String): Bool do
+ name = "{name}.{config.md_ext}"
+ return expand_path(config.root_dir, config.sidebar_dir, name).file_exists
+ end
+
+ # Load a markdown block with `name` from `WikiConfig::sidebar_dir`.
+ private fun load_sideblock(name: String): nullable String do
+ if not has_sideblock(name) then
+ message("Error: can't load sideblock `{name}`", 0)
+ return null
+ end
+ name = "{name}.{config.md_ext}"
+ var path = expand_path(config.root_dir, config.sidebar_dir, name)
+ var file = new FileReader.open(path)
+ var res = file.read_all
+ file.close
+ return res
+ end
+
# Join `parts` as a path and simplify it
fun expand_path(parts: String...): String do
var path = ""
# Used to translate ids in beautiful page names.
fun pretty_name(name: String): String do
name = name.replace("_", " ")
- name = name.capitalized
+ name = name.capitalized(keep_upper=true)
return name
end
end
# Returns `-1` if not `has_source`.
fun create_time: Int do
if not has_source then return -1
- return src_full_path.file_stat.ctime
+ return src_full_path.as(not null).file_stat.as(not null).ctime
end
# Entry last modification time.
# Returns `-1` if not `has_source`.
fun last_edit_time: Int do
if not has_source then return -1
- return src_full_path.file_stat.mtime
+ return src_full_path.as(not null).file_stat.as(not null).mtime
end
# Entry list rendering time.
# Returns `-1` if `is_new`.
fun last_render_time: Int do
if is_new then return -1
- return out_full_path.file_stat.mtime
+ return out_full_path.file_stat.as(not null).mtime
end
# Entries hierarchy
return path.reversed
end
+ # Sidebar relative to this wiki entry.
+ var sidebar = new WikiSidebar(self)
+
# Relative path from `wiki.config.root_dir` to source if any.
fun src_path: nullable String is abstract
# then returns the main wiki template file.
fun template_file: String do
if is_root then return wiki.config.template_file
- return parent.template_file
+ return parent.as(not null).template_file
end
# Header template file for `self`.
# Behave like `template_file`.
fun header_file: String do
if is_root then return wiki.config.header_file
- return parent.header_file
+ return parent.as(not null).header_file
end
# Footer template file for `self`.
# Behave like `template_file`.
fun footer_file: String do
if is_root then return wiki.config.footer_file
- return parent.footer_file
+ return parent.as(not null).footer_file
end
# Menu template file for `self`.
# Behave like `template_file`.
fun menu_file: String do
if is_root then return wiki.config.menu_file
- return parent.menu_file
+ return parent.as(not null).menu_file
end
# Display the entry `name`.
redef fun title do
if has_config then
- var title = config.title
+ var title = config.as(not null).title
if title != null then return title
end
return super
#
# Hidden section are rendered but not linked in menus.
fun is_hidden: Bool do
- if has_config then return config.is_hidden
+ if has_config then return config.as(not null).is_hidden
return false
end
if parent == null then
return wiki.config.source_dir
else
- return wiki.expand_path(parent.src_path, name)
+ return wiki.expand_path(parent.as(not null).src_path, name)
end
end
private fun try_load_config do
var cfile = wiki.expand_path(wiki.config.root_dir, src_path, wiki.config_filename)
if not cfile.file_exists then return
- wiki.message("Custom config for section {name}", 1)
+ wiki.message("Custom config for section {name}", 2)
config = new SectionConfig(cfile)
end
# Also check custom config.
redef fun template_file do
if has_config then
- var tpl = config.template_file
+ var tpl = config.as(not null).template_file
if tpl != null then return tpl
end
if is_root then return wiki.config.template_file
- return parent.template_file
+ return parent.as(not null).template_file
end
# Also check custom config.
redef fun header_file do
if has_config then
- var tpl = config.header_file
+ var tpl = config.as(not null).header_file
if tpl != null then return tpl
end
if is_root then return wiki.config.header_file
- return parent.header_file
+ return parent.as(not null).header_file
end
# Also check custom config.
redef fun footer_file do
if has_config then
- var tpl = config.footer_file
+ var tpl = config.as(not null).footer_file
if tpl != null then return tpl
end
if is_root then return wiki.config.footer_file
- return parent.footer_file
+ return parent.as(not null).footer_file
end
# Also check custom config.
redef fun menu_file do
if has_config then
- var tpl = config.menu_file
+ var tpl = config.as(not null).menu_file
if tpl != null then return tpl
end
if is_root then return wiki.config.menu_file
- return parent.menu_file
+ return parent.as(not null).menu_file
end
end
# Articles can only have `WikiSection` as parents.
redef type PARENT: WikiSection
- redef fun title: String do
+ redef fun title do
+ var parent = self.parent
if name == "index" and parent != null then return parent.title
return super
end
content = md
end
- redef var src_full_path: nullable String = null
+ redef var src_full_path = null
redef fun src_path do
+ var src_full_path = self.src_full_path
if src_full_path == null then return null
- return src_full_path.substring_from(wiki.config.root_dir.length)
+ var res = wiki.config.root_dir.relpath(src_full_path)
+ return res
end
# The page markdown source content.
# REQUIRE: `has_source`.
var md: nullable String is lazy do
if not has_source then return null
- var file = new FileReader.open(src_full_path.to_s)
+ var file = new FileReader.open(src_full_path.as(not null))
var md = file.read_all
file.close
return md
redef fun is_dirty do
if super then return true
if has_source then
- return wiki.need_render(src_full_path.to_s, out_full_path)
+ return wiki.need_render(src_full_path.as(not null), out_full_path)
end
return false
end
redef fun to_s do return "{name} ({parent or else "null"})"
end
+# The sidebar is displayed in front of the main panel of a `WikiEntry`.
+class WikiSidebar
+
+ # Wiki used to parse sidebar blocks.
+ var wiki: Nitiwiki is lazy do return entry.wiki
+
+ # WikiEntry this panel is related to.
+ var entry: WikiEntry
+
+ # Blocks are ieces of markdown that will be rendered in the sidebar.
+ var blocks: Array[Text] is lazy do
+ var res = new Array[Text]
+ # TODO get blocks from the entry for more customization
+ for name in entry.wiki.config.sidebar_blocks do
+ var block = wiki.load_sideblock(name)
+ if block == null then continue
+ res.add block
+ end
+ return res
+ end
+end
+
# Wiki configuration class.
#
# This class provides services that ensure static typing when accessing the `config.ini` file.
super ConfigTree
# Returns the config value at `key` or return `default` if no key was found.
- private fun value_or_default(key: String, default: String): String do
- if not has_key(key) then return default
- return self[key]
+ protected fun value_or_default(key: String, default: String): String do
+ return self[key] or else default
end
# Site name displayed.
# * default: ``
var wiki_logo: String is lazy do return value_or_default("wiki.logo", "")
- # Root url of the wiki.
- #
- # * key: `wiki.root_url`
- # * default: `http://localhost/`
- var root_url: String is lazy do return value_or_default("wiki.root_url", "http://localhost/")
-
# Markdown extension recognized by this wiki.
#
# We allow only one kind of extension per wiki.
return value_or_default("wiki.footer", "footer.html")
end
+ # Automatically add a summary.
+ #
+ # * key: `wiki.auto_summary`
+ # * default: `true`
+ var auto_summary: Bool is lazy do
+ return value_or_default("wiki.auto_summary", "true") == "true"
+ end
+
+ # Automatically add breadcrumbs.
+ #
+ # * key: `wiki.auto_breadcrumbs`
+ # * default: `true`
+ var auto_breadcrumbs: Bool is lazy do
+ return value_or_default("wiki.auto_breadcrumbs", "true") == "true"
+ end
+
# Sidebar position.
#
# Position of the sidebar between `left`, `right` and `none`. Any other value
return value_or_default("wiki.sidebar", "left")
end
+ # Sidebar markdown block to include.
+ #
+ # Blocks are specified by their filename without the extension.
+ #
+ # * key: `wiki.sidebar.blocks`
+ # * default: `[]`
+ var sidebar_blocks: Array[String] is lazy do
+ var res = new Array[String]
+ if not has_key("wiki.sidebar.blocks") then return res
+ for val in at("wiki.sidebar.blocks").as(not null).values do
+ res.add val
+ end
+ return res
+ end
+
+ # Sidebar files directory.
+ #
+ # Directory where sidebar blocks are stored.
+ # **This path MUST be relative to `root_dir`.**
+ #
+ # * key: `wiki.sidebar_dir`
+ # * default: `sidebar/`
+ var sidebar_dir: String is lazy do
+ return value_or_default("wiki.sidebar_dir", "sidebar/").simplify_path
+ end
+
# Directory used by rsync to upload wiki files.
#
# This information is used to update your distant wiki files (like the webserver).
# * key: `wiki.git_branch`
# * default: `master`
var git_branch: String is lazy do return value_or_default("wiki.git_branch", "master")
+
+ # URL to source versionning used to display last changes
+ #
+ # * key: `wiki.last_changes`
+ # * default: ``
+ var last_changes: String is lazy do return value_or_default("wiki.last_changes", "")
+
+ # URL to source edition.
+ #
+ # * key: `wiki.edit`
+ # * default: ``
+ var edit: String is lazy do return value_or_default("wiki.edit", "")
end
# WikiSection custom configuration.