Include HTML docs in minimal installs (#856)
* Link to stable docs for stable release, otherwise latest docs * Add build command to setup for making HTML docs * Change the documentation menu entry to open either online or local HTML * Update docs build instructions in docs
This commit is contained in:
committed by
GitHub
parent
a9368904e5
commit
eee0f5e4c9
@@ -17,6 +17,7 @@ i18n/*.qph
|
|||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
/docs/build/
|
/docs/build/
|
||||||
|
/nw/assets/help/html/
|
||||||
*.qch
|
*.qch
|
||||||
*.qhc
|
*.qhc
|
||||||
|
|
||||||
|
|||||||
@@ -141,13 +141,12 @@ generated. It requires the following Python packages on Debian and Ubuntu.
|
|||||||
|
|
||||||
* ``python3-sphinx``
|
* ``python3-sphinx``
|
||||||
* ``python3-sphinx-rtd-theme``
|
* ``python3-sphinx-rtd-theme``
|
||||||
* ``python3-sphinxcontrib.qthelp``
|
|
||||||
|
|
||||||
Or from PyPi:
|
Or from PyPi:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
pip install sphinx sphinx-rtd-theme sphinxcontrib-qthelp
|
pip install sphinx sphinx-rtd-theme
|
||||||
|
|
||||||
The documentation can then be built from the ``docs`` folder in the source code by running:
|
The documentation can then be built from the ``docs`` folder in the source code by running:
|
||||||
|
|
||||||
@@ -158,19 +157,13 @@ The documentation can then be built from the ``docs`` folder in the source code
|
|||||||
If successful, the documentation should be available in the ``docs/build/html`` folder and you can
|
If successful, the documentation should be available in the ``docs/build/html`` folder and you can
|
||||||
open the ``index.html`` file in your browser.
|
open the ``index.html`` file in your browser.
|
||||||
|
|
||||||
The documentation can also be built for the Qt Assistant. To build the help packages from the
|
You can also build the documentation by using the setup script:
|
||||||
documentation source, run the following from the root source folder:
|
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
python setup.py qthelp
|
python setup.py docs
|
||||||
|
|
||||||
The setup script will copy the generated files into the ``nw/assets/help`` folder, and novelWriter
|
This does the same as the ``make help`` command, but in addition it copies the documentation into
|
||||||
will detect the presence of the files and redirect the menu help entry to open help locally instead
|
novelWriter's assets folder. This will make it possible to open the documentation from inside of
|
||||||
of sending the user to the website. Pressing the :kbd:`F1` key will in any case try to open help
|
novelWriter by pressing :kbd:`F1` even without an internet connection, as it will instead open the
|
||||||
locally first, then send you to the website as a fallback.
|
local copy.
|
||||||
|
|
||||||
.. note::
|
|
||||||
In order for the local version of help to work, the Qt Assistant must be installed on the local
|
|
||||||
computer. If it isn't available, or novelWriter cannot find it, the help feature will fall back
|
|
||||||
to redirecting you to the documentation website.
|
|
||||||
|
|||||||
+1
-17
@@ -26,7 +26,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import shutil
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
@@ -72,11 +71,9 @@ class Config:
|
|||||||
self.themeRoot = None # The full path to the nw/assets/themes folder
|
self.themeRoot = None # The full path to the nw/assets/themes folder
|
||||||
self.dictPath = None # The full path to the nw/assets/dict folder
|
self.dictPath = None # The full path to the nw/assets/dict folder
|
||||||
self.iconPath = None # The full path to the nw/assets/icons folder
|
self.iconPath = None # The full path to the nw/assets/icons folder
|
||||||
self.helpPath = None # The full path to the novelwriter .qhc help file
|
|
||||||
|
|
||||||
# Runtime Settings and Variables
|
# Runtime Settings and Variables
|
||||||
self.confChanged = False # True whenever the config has chenged, false after save
|
self.confChanged = False # True whenever the config has chenged, false after save
|
||||||
self.hasHelp = False # True if the Qt help files are present in the assets folder
|
|
||||||
|
|
||||||
# General
|
# General
|
||||||
self.guiTheme = "default"
|
self.guiTheme = "default"
|
||||||
@@ -230,8 +227,7 @@ class Config:
|
|||||||
self.kernelVer = "Unknown"
|
self.kernelVer = "Unknown"
|
||||||
|
|
||||||
# Packages
|
# Packages
|
||||||
self.hasEnchant = False # The pyenchant package
|
self.hasEnchant = False # The pyenchant package
|
||||||
self.hasAssistant = False # The Qt Assistant executable
|
|
||||||
|
|
||||||
# Recent Cache
|
# Recent Cache
|
||||||
self.recentProj = {}
|
self.recentProj = {}
|
||||||
@@ -360,11 +356,6 @@ class Config:
|
|||||||
if self.spellLanguage is None:
|
if self.spellLanguage is None:
|
||||||
self.spellLanguage = "en"
|
self.spellLanguage = "en"
|
||||||
|
|
||||||
# Check if local help files exist
|
|
||||||
self.helpPath = os.path.join(self.assetPath, "help", "novelWriter.qhc")
|
|
||||||
self.hasHelp = os.path.isfile(self.helpPath)
|
|
||||||
self.hasHelp &= os.path.isfile(os.path.join(self.assetPath, "help", "novelWriter.qch"))
|
|
||||||
|
|
||||||
logger.debug("Config initialisation complete")
|
logger.debug("Config initialisation complete")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -930,13 +921,6 @@ class Config:
|
|||||||
self.hasEnchant = False
|
self.hasEnchant = False
|
||||||
logger.debug("Checking package 'pyenchant': Missing")
|
logger.debug("Checking package 'pyenchant': Missing")
|
||||||
|
|
||||||
assistPath = shutil.which("assistant")
|
|
||||||
self.hasAssistant = assistPath is not None
|
|
||||||
if self.hasAssistant:
|
|
||||||
logger.debug("Checking executable 'assistant': OK")
|
|
||||||
else:
|
|
||||||
logger.debug("Checking executable 'assistant': Missing")
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# END Class Config
|
# END Class Config
|
||||||
|
|||||||
+38
-57
@@ -23,10 +23,15 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
import nw
|
import nw
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from PyQt5.QtCore import QUrl, QProcess
|
from http.client import HTTPSConnection
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
from urllib.request import pathname2url
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QUrl
|
||||||
from PyQt5.QtGui import QDesktopServices
|
from PyQt5.QtGui import QDesktopServices
|
||||||
from PyQt5.QtWidgets import QMenuBar, QAction
|
from PyQt5.QtWidgets import QMenuBar, QAction
|
||||||
|
|
||||||
@@ -46,9 +51,6 @@ class GuiMainMenu(QMenuBar):
|
|||||||
self.theParent = theParent
|
self.theParent = theParent
|
||||||
self.theProject = theParent.theProject
|
self.theProject = theParent.theProject
|
||||||
|
|
||||||
# Internals
|
|
||||||
self._assistProc = None
|
|
||||||
|
|
||||||
# Build Menu
|
# Build Menu
|
||||||
self._buildProjectMenu()
|
self._buildProjectMenu()
|
||||||
self._buildDocumentMenu()
|
self._buildDocumentMenu()
|
||||||
@@ -89,25 +91,6 @@ class GuiMainMenu(QMenuBar):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
def closeHelp(self):
|
|
||||||
"""Close the process used for the Qt Assistant, if it is open.
|
|
||||||
"""
|
|
||||||
if self._assistProc is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
if self._assistProc.state() == QProcess.Starting:
|
|
||||||
if self._assistProc.waitForStarted(10000):
|
|
||||||
self._assistProc.terminate()
|
|
||||||
else:
|
|
||||||
self._assistProc.kill()
|
|
||||||
|
|
||||||
elif self._assistProc.state() == QProcess.Running:
|
|
||||||
self._assistProc.terminate()
|
|
||||||
if not self._assistProc.waitForFinished(10000):
|
|
||||||
self._assistProc.kill()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Update Menu on Settings Changed
|
# Update Menu on Settings Changed
|
||||||
##
|
##
|
||||||
@@ -148,28 +131,38 @@ class GuiMainMenu(QMenuBar):
|
|||||||
self.theProject.setAutoOutline(theMode)
|
self.theProject.setAutoOutline(theMode)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _openAssistant(self, isChecked=False):
|
|
||||||
"""Open the documentation in Qt Assistant.
|
|
||||||
"""
|
|
||||||
if not self.mainConf.hasHelp:
|
|
||||||
self._openWebsite(nw.__docurl__)
|
|
||||||
return False
|
|
||||||
|
|
||||||
self._assistProc = QProcess(self)
|
|
||||||
self._assistProc.start("assistant", ["-collectionFile", self.mainConf.helpPath])
|
|
||||||
|
|
||||||
if not self._assistProc.waitForStarted(10000):
|
|
||||||
self._openWebsite(nw.__docurl__)
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _openWebsite(self, theUrl):
|
def _openWebsite(self, theUrl):
|
||||||
"""Open a URL in the system's default browser.
|
"""Open a URL in the system's default browser.
|
||||||
"""
|
"""
|
||||||
QDesktopServices.openUrl(QUrl(theUrl))
|
QDesktopServices.openUrl(QUrl(theUrl))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _openDocumentation(self):
|
||||||
|
"""Open the documentation, and select whether it should be the
|
||||||
|
stable or latest version. If no internet connection, open
|
||||||
|
local.
|
||||||
|
"""
|
||||||
|
if nw.__hexversion__[-2] == "f":
|
||||||
|
docsPath = "/en/stable/"
|
||||||
|
else:
|
||||||
|
docsPath = "/en/latest/"
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = HTTPSConnection(nw.__docurl__.replace("https://", ""))
|
||||||
|
conn.request("HEAD", docsPath)
|
||||||
|
resp = conn.getresponse()
|
||||||
|
hasAccess = resp.code == 200
|
||||||
|
except Exception:
|
||||||
|
hasAccess = False
|
||||||
|
|
||||||
|
docsFile = os.path.join(self.mainConf.assetPath, "help", "html", "index.html")
|
||||||
|
if hasAccess or not os.path.isfile(docsFile):
|
||||||
|
self._openWebsite(nw.__docurl__ + docsPath)
|
||||||
|
else:
|
||||||
|
self._openWebsite(urljoin("file:", pathname2url(docsFile)))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Menu Builders
|
# Menu Builders
|
||||||
##
|
##
|
||||||
@@ -1113,24 +1106,12 @@ class GuiMainMenu(QMenuBar):
|
|||||||
# Help > Separator
|
# Help > Separator
|
||||||
self.helpMenu.addSeparator()
|
self.helpMenu.addSeparator()
|
||||||
|
|
||||||
# Document > Documentation
|
# Help > Documentation
|
||||||
if self.mainConf.hasHelp and self.mainConf.hasAssistant:
|
self.aHelpDocs = QAction(self.tr("Documentation"), self)
|
||||||
self.aHelpLoc = QAction(self.tr("Documentation (Local)"), self)
|
self.aHelpDocs.setStatusTip(self.tr("Open documentation in browser"))
|
||||||
self.aHelpLoc.setStatusTip(self.tr("View local documentation with Qt Assistant"))
|
self.aHelpDocs.triggered.connect(self._openDocumentation)
|
||||||
self.aHelpLoc.triggered.connect(self._openAssistant)
|
self.aHelpDocs.setShortcut("F1")
|
||||||
self.aHelpLoc.setShortcut("F1")
|
self.helpMenu.addAction(self.aHelpDocs)
|
||||||
self.helpMenu.addAction(self.aHelpLoc)
|
|
||||||
|
|
||||||
self.aHelpWeb = QAction(self.tr("Documentation (Online)"), self)
|
|
||||||
self.aHelpWeb.setStatusTip(
|
|
||||||
self.tr("View online documentation at {0}").format(nw.__docurl__)
|
|
||||||
)
|
|
||||||
self.aHelpWeb.triggered.connect(lambda: self._openWebsite(nw.__docurl__))
|
|
||||||
if self.mainConf.hasHelp and self.mainConf.hasAssistant:
|
|
||||||
self.aHelpWeb.setShortcut("Shift+F1")
|
|
||||||
else:
|
|
||||||
self.aHelpWeb.setShortcuts(["F1", "Shift+F1"])
|
|
||||||
self.helpMenu.addAction(self.aHelpWeb)
|
|
||||||
|
|
||||||
# Help > Separator
|
# Help > Separator
|
||||||
self.helpMenu.addSeparator()
|
self.helpMenu.addSeparator()
|
||||||
|
|||||||
+1
-4
@@ -1190,7 +1190,6 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
self.mainConf.saveConfig()
|
self.mainConf.saveConfig()
|
||||||
self.reportConfErr()
|
self.reportConfErr()
|
||||||
self.mainMenu.closeHelp()
|
|
||||||
|
|
||||||
qApp.quit()
|
qApp.quit()
|
||||||
|
|
||||||
@@ -1373,9 +1372,7 @@ class GuiMain(QMainWindow):
|
|||||||
self.addAction(self.mainMenu.aPreferences)
|
self.addAction(self.mainMenu.aPreferences)
|
||||||
|
|
||||||
# Help
|
# Help
|
||||||
if self.mainConf.hasHelp and self.mainConf.hasAssistant:
|
self.addAction(self.mainMenu.aHelpDocs)
|
||||||
self.addAction(self.mainMenu.aHelpLoc)
|
|
||||||
self.addAction(self.mainMenu.aHelpWeb)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -221,6 +221,56 @@ def buildQtDocs():
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Html Documentation Builder (docs)
|
||||||
|
##
|
||||||
|
|
||||||
|
def buildHtmlDocs():
|
||||||
|
"""This function will build the Sphinx HTML documentation. The files
|
||||||
|
are then copied into the nw/assets/help/html directory and can be
|
||||||
|
included in builds.
|
||||||
|
"""
|
||||||
|
buildDir = os.path.join("docs", "build", "html")
|
||||||
|
helpDir = os.path.join("nw", "assets", "help", "html")
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("Building Documentation")
|
||||||
|
print("======================")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
buildFail = False
|
||||||
|
try:
|
||||||
|
subprocess.call(["make", "-C", "docs", "clean"])
|
||||||
|
subprocess.call(["make", "-C", "docs", "html"])
|
||||||
|
except Exception as e:
|
||||||
|
print("Docs Build Error:")
|
||||||
|
print(str(e))
|
||||||
|
buildFail = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.isdir(helpDir):
|
||||||
|
shutil.rmtree(helpDir)
|
||||||
|
shutil.copytree(buildDir, helpDir)
|
||||||
|
except Exception as e:
|
||||||
|
print("Docs Build Error:")
|
||||||
|
print(str(e))
|
||||||
|
buildFail = True
|
||||||
|
|
||||||
|
print("")
|
||||||
|
if buildFail:
|
||||||
|
print("Documentation build: FAILED")
|
||||||
|
print("")
|
||||||
|
print("Dependencies:")
|
||||||
|
print(" * pip install sphinx")
|
||||||
|
print(" * pip install sphinx-rtd-theme")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Documentation build: OK")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Qt Linguist QM Builder (qtlrelease)
|
# Qt Linguist QM Builder (qtlrelease)
|
||||||
##
|
##
|
||||||
@@ -349,6 +399,14 @@ def makeMinimalPackage(targetOS):
|
|||||||
print(str(e))
|
print(str(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Build docs
|
||||||
|
try:
|
||||||
|
buildHtmlDocs()
|
||||||
|
except Exception as e:
|
||||||
|
print("Failed with error:")
|
||||||
|
print(str(e))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Make translation files
|
# Make translation files
|
||||||
try:
|
try:
|
||||||
buildQtI18n()
|
buildQtI18n()
|
||||||
@@ -1137,6 +1195,7 @@ if __name__ == "__main__":
|
|||||||
"",
|
"",
|
||||||
"Additional Builds:",
|
"Additional Builds:",
|
||||||
"",
|
"",
|
||||||
|
" docs Build the help documentation as HTML."
|
||||||
" qthelp Build the help documentation for use with the Qt Assistant.",
|
" qthelp Build the help documentation for use with the Qt Assistant.",
|
||||||
" qtlupdate Update the translation files for internationalisation.",
|
" qtlupdate Update the translation files for internationalisation.",
|
||||||
" qtlrelease Build the language files for internationalisation.",
|
" qtlrelease Build the language files for internationalisation.",
|
||||||
@@ -1203,6 +1262,10 @@ if __name__ == "__main__":
|
|||||||
# Additional Builds
|
# Additional Builds
|
||||||
# =================
|
# =================
|
||||||
|
|
||||||
|
if "docs" in sys.argv:
|
||||||
|
sys.argv.remove("docs")
|
||||||
|
buildHtmlDocs()
|
||||||
|
|
||||||
if "qthelp" in sys.argv:
|
if "qthelp" in sys.argv:
|
||||||
sys.argv.remove("qthelp")
|
sys.argv.remove("qthelp")
|
||||||
buildQtDocs()
|
buildQtDocs()
|
||||||
|
|||||||
@@ -544,14 +544,4 @@ def testBaseConfig_Internal(monkeypatch, tmpConf):
|
|||||||
tmpConf._checkOptionalPackages()
|
tmpConf._checkOptionalPackages()
|
||||||
assert tmpConf.hasEnchant is False
|
assert tmpConf.hasEnchant is False
|
||||||
|
|
||||||
with monkeypatch.context() as mp:
|
|
||||||
mp.setattr("shutil.which", lambda *a: "stuff")
|
|
||||||
tmpConf._checkOptionalPackages()
|
|
||||||
assert tmpConf.hasAssistant is True
|
|
||||||
|
|
||||||
with monkeypatch.context() as mp:
|
|
||||||
mp.setattr("shutil.which", lambda *a: None)
|
|
||||||
tmpConf._checkOptionalPackages()
|
|
||||||
assert tmpConf.hasAssistant is False
|
|
||||||
|
|
||||||
# END Test testBaseConfig_Internal
|
# END Test testBaseConfig_Internal
|
||||||
|
|||||||
Reference in New Issue
Block a user