diff options
author | Patrick Griffis <pgriffis@igalia.com> | 2020-11-03 17:19:06 -0600 |
---|---|---|
committer | Patrick Griffis <pgriffis@igalia.com> | 2020-11-03 17:19:06 -0600 |
commit | b07c7ba4e55fbe29c5511bb9f937005be2208326 (patch) | |
tree | ce8878875a7fd58304f1afb310c7988a4b2d4174 | |
parent | 3485d82b7fc4451006f9b5a94fe143efab9b2a9d (diff) | |
download | libsoup-wip/pgriffis/markdown-docs.tar.gz |
WIP: Try using markdown for docswip/pgriffis/markdown-docs
-rw-r--r-- | docs/reference/client-howto.md | 45 | ||||
-rw-r--r-- | docs/reference/client-howto.xml | 548 | ||||
-rwxr-xr-x | docs/reference/gtk-markdown-to-docbook.py | 201 | ||||
-rw-r--r-- | docs/reference/meson.build | 33 |
4 files changed, 274 insertions, 553 deletions
diff --git a/docs/reference/client-howto.md b/docs/reference/client-howto.md new file mode 100644 index 00000000..431b667c --- /dev/null +++ b/docs/reference/client-howto.md @@ -0,0 +1,45 @@ +# libsoup Client Basics {#libsoup-client-howto} + +This section explains how to use libsoup as an HTTP client using several new APIs introduced in version 2.42. +If you want to be compatible with older versions of libsoup, consult the documentation for that version. + + +## Creating a SoupSession + +The first step in using the client API is to create a #SoupSession. +The session object encapsulates all of the state that libsoup +is keeping on behalf of your program; cached HTTP connections, +authentication information, etc. + +When you create the session with soup_session_new_with_options(), +you can specify various additional options: + +- ["max-conns"](#SoupSession:max-conns) + + Allows you to set the maximum total number of connections + the session will have open at one time. (Once it reaches + this limit, it will either close idle connections, or + wait for existing connections to free up before starting + new requests.) The default value is `10`. + +- ["max-conns-per-host"](#SoupSession:max-conns-per-host) + + Allows you to set the maximum total number of connections + the session will have open *to a single host* at one time. + The default value is `2`. + +- ["user-agent"](#SoupSession:user-agent) + + Allows you to set a User-Agent string that will be sent + on all outgoing requests. + +Other properties are also available; see the #SoupSession documentation +for more details. + +If you don't need to specify any options, you can just use soup_session_new(), +which takes no arguments. + +## Session features + +Additional session functionality is provided as #SoupSessionFeature<!-- -->s, +which can be added to a session...
\ No newline at end of file diff --git a/docs/reference/client-howto.xml b/docs/reference/client-howto.xml deleted file mode 100644 index d9c558ae..00000000 --- a/docs/reference/client-howto.xml +++ /dev/null @@ -1,548 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" - "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"> -<refentry id="libsoup-client-howto"> -<refmeta> -<refentrytitle>libsoup Client Basics</refentrytitle> -<manvolnum>3</manvolnum> -<refmiscinfo>LIBSOUP Library</refmiscinfo> -</refmeta> - -<refnamediv> -<refname>libsoup Client Basics</refname><refpurpose>Client-side tutorial</refpurpose> -</refnamediv> - -<refsect2> -<para> -This section explains how to use <application>libsoup</application> as -an HTTP client using several new APIs introduced in version 2.42. If -you want to be compatible with older versions of -<application>libsoup</application>, consult the documentation for that -version. -</para> -</refsect2> - -<refsect2> -<title>Creating a <type>SoupSession</type></title> - -<para> -The first step in using the client API is to create a <link -linkend="SoupSession"><type>SoupSession</type></link>. The session object -encapsulates all of the state that <application>libsoup</application> -is keeping on behalf of your program; cached HTTP connections, -authentication information, etc. -</para> - -<para> -When you create the session with <link -linkend="soup-session-new-with-options"><function>soup_session_new_with_options</function></link>, -you can specify various additional options: -</para> - -<variablelist> - <varlistentry> - <term><link linkend="SoupSession:max-conns"><literal>"max-conns"</literal></link></term> - <listitem><para> - Allows you to set the maximum total number of connections - the session will have open at one time. (Once it reaches - this limit, it will either close idle connections, or - wait for existing connections to free up before starting - new requests.) The default value is 10. - </para></listitem> - </varlistentry> - <varlistentry> - <term><link linkend="SoupSession:max-conns-per-host"><literal>"max-conns-per-host"</literal></link></term> - <listitem><para> - Allows you to set the maximum total number of connections - the session will have open <emphasis>to a single - host</emphasis> at one time. The default value is 2. - </para></listitem> - </varlistentry> - <varlistentry> - <term><link linkend="SoupSession:user-agent"><literal>"user-agent"</literal></link></term> - <listitem><para> - Allows you to set a User-Agent string that will be sent - on all outgoing requests. - </para></listitem> - </varlistentry> - <varlistentry> - <term><link linkend="SoupSession:accept-language"><literal>"accept-language"</literal></link> - and <link linkend="SoupSession:accept-language-auto"><literal>"accept-language-auto"</literal></link></term> - <listitem><para> - Allow you to set an Accept-Language header on all outgoing - requests. <literal>"accept-language"</literal> - takes a list of language tags to use, while - <literal>"accept-language-auto"</literal> - automatically generates the list from the user's locale - settings. - </para></listitem> - </varlistentry> - <varlistentry> - <term><link linkend="SoupSession:http-aliases"><literal>"http-aliases"</literal></link> - and <link linkend="SoupSession:https-aliases"><literal>"https-aliases"</literal></link></term> - <listitem><para> - Allow you to tell the session to recognize additional URI - schemes as aliases for "<literal>http</literal>" or - <literal>https</literal>. You can set this if you are - using URIs with schemes like "<literal>dav</literal>" or - "<literal>webcal</literal>" (and in particular, you need - to set this if the server you are talking to might return - redirects with such a scheme). - </para></listitem> - </varlistentry> - <varlistentry> - <term><link linkend="SoupSession:proxy-resolver"><literal>"proxy-resolver"</literal></link></term> - <listitem> - <para> - <link linkend="SoupSession:proxy-resolver"><literal>"proxy-resolver"</literal></link> - specifies a <link - linkend="GProxyResolver"><type>GProxyResolver</type></link> - to use to determine the HTTP proxies to use. By default, - this is set to the resolver returned by <link - linkend="g-proxy-resolver-get-default"><function>g_proxy_resolver_get_default</function></link>, - so you do not need to set it yourself. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><link linkend="SoupSession:add-feature"><literal>"add-feature"</literal></link> and <link linkend="SOUP-SESSION-ADD-FEATURE-BY-TYPE:CAPS"><literal>"add-feature-by-type"</literal></link></term> - <listitem><para> - These allow you to specify <link - linkend="SoupSessionFeature"><type>SoupSessionFeature</type></link>s - (discussed <link linkend="session-features">below</link>) - to add at construct-time. - </para></listitem> - </varlistentry> -</variablelist> - -<para> -Other properties are also available; see the <link -linkend="SoupSession"><type>SoupSession</type></link> documentation for -more details. -</para> - -<para> -If you don't need to specify any options, you can just use <link -linkend="soup-session-new"><function>soup_session_new</function></link>, -which takes no arguments. -</para> - -</refsect2> - -<refsect2 id="session-features"> -<title>Session features</title> - -<para> -Additional session functionality is provided as <link -linkend="SoupSessionFeature"><type>SoupSessionFeature</type></link>s, -which can be added to a session, via the <link -linkend="SoupSession:add-feature"><literal>"add-feature"</literal></link> -and <link -linkend="SoupSession:add-feature-by-type"><literal>"add-feature-by-type"</literal></link> -options at session-construction-time, or afterward via the <link -linkend="soup-session-add-feature"><function>soup_session_add_feature</function></link> -and <link -linkend="soup-session-add-feature-by-type"><function>soup_session_add_feature_by_type</function></link> -functions. -</para> - -<para> -A <link -linkend="SoupContentDecoder"><type>SoupContentDecoder</type></link> is -added for you automatically. This advertises to servers that the -client supports compression, and automatically decompresses compressed -responses. -</para> - -<para> -Some other available features that you can add include: -</para> - -<variablelist> - <varlistentry> - <term><link linkend="SoupLogger"><type>SoupLogger</type></link></term> - <listitem><para> - A debugging aid, which logs all of libsoup's HTTP traffic - to <literal>stdout</literal> (or another place you specify). - </para></listitem> - </varlistentry> - <varlistentry> - <term> - <link linkend="SoupCookieJar"><type>SoupCookieJar</type></link>, - <link linkend="SoupCookieJarText"><type>SoupCookieJarText</type></link>, - and <link linkend="SoupCookieJarDB"><type>SoupCookieJarDB</type></link> - </term> - <listitem><para> - Support for HTTP cookies. <type>SoupCookieJar</type> - provides non-persistent cookie storage, while - <type>SoupCookieJarText</type> uses a text file to keep - track of cookies between sessions, and - <type>SoupCookieJarDB</type> uses a - <application>SQLite</application> database. - </para></listitem> - </varlistentry> - <varlistentry> - <term><link linkend="SoupContentSniffer"><type>SoupContentSniffer</type></link></term> - <listitem><para> - Uses the HTML5 sniffing rules to attempt to - determine the Content-Type of a response when the - server does not identify the Content-Type, or appears to - have provided an incorrect one. - </para></listitem> - </varlistentry> -</variablelist> - -<para> -Use the "add_feature_by_type" property/function to add features that -don't require any configuration (such as <link -linkend="SoupContentSniffer"><type>SoupContentSniffer</type></link>), -and the "add_feature" property/function to add features that must be -constructed first (such as <link -linkend="SoupLogger"><type>SoupLogger</type></link>). For example, an -application might do something like the following: -</para> - -<informalexample><programlisting> - session = soup_session_new_with_options ( - "add-feature-by-type", SOUP_TYPE_CONTENT_SNIFFER, - NULL); - - if (debug_level) { - SoupLogger *logger; - - logger = soup_logger_new (debug_level, -1); - soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger)); - g_object_unref (logger); - } -</programlisting></informalexample> - -</refsect2> - -<refsect2> -<title>Creating and Sending SoupMessages</title> - -<para> -Once you have a session, you send HTTP requests using <link -linkend="SoupMessage"><type>SoupMessage</type></link>. In the simplest -case, you only need to create the message and it's ready to send: -</para> - -<informalexample><programlisting> - SoupMessage *msg; - - msg = soup_message_new ("GET", "http://example.com/"); -</programlisting></informalexample> - -<para> -In more complicated cases, you can use various <link -linkend="SoupMessage">SoupMessage</link>, <link -linkend="SoupMessageHeaders">SoupMessageHeaders</link>, and <link -linkend="SoupMessageBody">SoupMessageBody</link> methods to set the -request headers and body of the message: -</para> - -<informalexample><programlisting> - SoupMessage *msg; - - msg = soup_message_new ("POST", "http://example.com/form.cgi"); - soup_message_set_request (msg, "application/x-www-form-urlencoded", - SOUP_MEMORY_COPY, formdata, strlen (formdata)); - soup_message_headers_append (msg->request_headers, "Referer", referring_url); -</programlisting></informalexample> - -<para> -(Although this is a bad example, because -<application>libsoup</application> actually has convenience methods -for dealing with <link linkend="libsoup-3.0-HTML-Form-Support">HTML -forms</link>.) -</para> - -<para> -You can also use <link -linkend="soup-message-set-flags"><function>soup_message_set_flags</function></link> -to change some default behaviors. For example, by default, -<type>SoupSession</type> automatically handles responses from the -server that redirect to another URL. If you would like to handle these -yourself, you can set the <link linkend="SOUP-MESSAGE-NO-REDIRECT:CAPS"><literal>SOUP_MESSAGE_NO_REDIRECT</literal></link> -flag. -</para> - -<refsect3> -<title>Sending a Message Synchronously</title> - -<para> -To send a message and wait for the response, use <link -linkend="soup-session-send"><function>soup_session_send</function></link>: -</para> - -<informalexample><programlisting> - GInputStream *stream; - GError *error = NULL; - - stream = soup_session_send (session, msg, cancellable, &error); -</programlisting></informalexample> - -<para> -At the point when <function>soup_session_send</function> returns, the -request will have been sent, and the response headers read back in; -you can examine the message's <structfield>status_code</structfield>, -<structfield>reason_phrase</structfield>, and -<structfield>response_headers</structfield> fields to see the response -metadata. To get the response body, read from the returned <link -linkend="GInputStream"><type>GInputStream</type></link>, and close it -when you are done. -</para> - -<para> -Note that <function>soup_session_send</function> only returns an error -if a transport-level problem occurs (eg, it could not connect to the -host, or the request was cancelled). Use the message's -<structfield>status_code</structfield> field to determine whether the -request was successful or not at the HTTP level (ie, "<literal>200 -OK</literal>" vs "<literal>401 Bad Request</literal>"). -</para> - -<para> -If you would prefer to have <application>libsoup</application> gather -the response body for you and then return it all at once, you can use -the older -<link linkend="soup-session-send-message"><function>soup_session_send_message</function></link> -API: -</para> - -<informalexample><programlisting> - guint status; - - status = soup_session_send_message (session, msg); -</programlisting></informalexample> - -<para> -In this case, the response body will be available in the message's -<structfield>response_body</structfield> field, and transport-level -errors will be indicated in the <structfield>status_code</structfield> -field via special pseudo-HTTP-status codes like <link -linkend="SOUP-STATUS-CANT-CONNECT:CAPS"><literal>SOUP_STATUS_CANT_CONNECT</literal></link>. -</para> - -</refsect3> - -<refsect3> -<title>Sending a Message Asynchronously</title> - -<para> -To send a message asynchronously, use <link -linkend="soup-session-send-async"><function>soup_session_send_async</function></link>: -</para> - -<informalexample><programlisting> -{ - ... - soup_session_send_async (session, msg, cancellable, my_callback, my_callback_data); - ... -} - -static void -my_callback (GObject *object, GAsyncResult *result, gpointer user_data) -{ - GInputStream *stream; - GError *error = NULL; - - stream = soup_session_send_finish (SOUP_SESSION (object), result, &error); - ... -} -</programlisting></informalexample> - -<para> -The message will be added to the session's queue, and eventually (when -control is returned back to the main loop), it will be sent and the -response will be read. When the message has been sent, and its -headers received, the callback will be invoked, in the standard -<link linkend="GAsyncReadyCallback"><type>GAsyncReadyCallback</type></link> -style. -</para> - -<para> -As with synchronous sending, there is also an alternate API, <link -linkend="soup-session-queue-message"><function>soup_session_queue_message</function></link>, -in which your callback is not invoked until the response has been -completely read: -</para> - -<informalexample><programlisting> -{ - ... - soup_session_queue_message (session, msg, my_callback, my_callback_data); - ... -} - -static void -my_callback (SoupSession *session, SoupMessage *msg, gpointer user_data) -{ - /* msg->response_body contains the response */ -} -</programlisting></informalexample> - -<para> -<link -linkend="soup-session-queue-message"><function>soup_session_queue_message</function></link> -is slightly unusual in that it steals a reference to the message -object, and unrefs it after the last callback is invoked on it. So -when using this API, you should not unref the message yourself. -</para> - -</refsect3> - -</refsect2> - -<refsect2> -<title>Processing the Response</title> - -<para> -Once you have received the initial response from the server, -synchronously or asynchronously, streaming or not, you can look at the -response fields in the <literal>SoupMessage</literal> to decide what -to do next. The <structfield>status_code</structfield> and -<structfield>reason_phrase</structfield> fields contain the numeric -status and textual status response from the server. -<structfield>response_headers</structfield> contains the response -headers, which you can investigate using <link -linkend="soup-message-headers-get-list"><function>soup_message_headers_get_list</function></link> -and <link -linkend="soup-message-headers-foreach"><function>soup_message_headers_foreach</function></link>. -</para> - -<para> -<link -linkend="SoupMessageHeaders"><type>SoupMessageHeaders</type></link> -automatically parses several important headers in -<structfield>response_headers</structfield> for you and provides -specialized accessors for them. Eg, <link -linkend="soup-message-headers-get-content-type"><function>soup_message_headers_get_content_type</function></link>. -There are several generic methods such as <link -linkend="soup-header-parse-param-list"><function>soup_header_parse_param_list</function></link> -(for parsing an attribute-list-type header) and <link -linkend="soup-header-contains"><function>soup_header_contains</function></link> -(for quickly testing if a list-type header contains a particular -token). These handle the various syntactical oddities of parsing HTTP -headers much better than functions like -<function>g_strsplit</function> or <function>strstr</function>. -</para> - -</refsect2> - -<refsect2> -<title>Handling Authentication</title> - -<para> -<type>SoupSession</type> handles most of the details of HTTP -authentication for you. If it receives a 401 ("Unauthorized") or 407 -("Proxy Authentication Required") response, the session will emit the -<link linkend="SoupSession-authenticate">authenticate</link> signal, -providing you with a <link -linkend="SoupAuth"><type>SoupAuth</type></link> object indicating the -authentication type ("Basic", "Digest", or "NTLM") and the realm name -provided by the server. If you have a username and password available -(or can generate one), call <link -linkend="soup-auth-authenticate"><function>soup_auth_authenticate</function></link> -to give the information to libsoup. The session will automatically -requeue the message and try it again with that authentication -information. (If you don't call -<function>soup_auth_authenticate</function>, the session will just -return the message to the application with its 401 or 407 status.) -</para> - -<para> -If the server doesn't accept the username and password provided, the -session will emit <link -linkend="SoupSession-authenticate">authenticate</link> again, with the -<literal>retrying</literal> parameter set to <literal>TRUE</literal>. This lets the -application know that the information it provided earlier was -incorrect, and gives it a chance to try again. If this -username/password pair also doesn't work, the session will contine to -emit <literal>authenticate</literal> again and again until the -provided username/password successfully authenticates, or until the -signal handler fails to call <link -linkend="soup-auth-authenticate"><function>soup_auth_authenticate</function></link>, -at which point <application>libsoup</application> will allow the -message to fail (with status 401 or 407). -</para> - -<para> -If you need to handle authentication asynchronously (eg, to pop up a -password dialog without recursively entering the main loop), you can -do that as well. Just call <link -linkend="soup-session-pause-message"><function>soup_session_pause_message</function></link> -on the message before returning from the signal handler, and -<function>g_object_ref</function> the <type>SoupAuth</type>. Then, -later on, after calling <function>soup_auth_authenticate</function> -(or deciding not to), call <link -linkend="soup-session-unpause-message"><function>soup_session_unpause_message</function></link> -to resume the paused message. -</para> - -<para> -By default, NTLM authentication is not enabled. To add NTLM support to -a session, call: -</para> - -<informalexample><programlisting> - soup_session_add_feature_by_type (session, SOUP_TYPE_AUTH_NTLM); -</programlisting></informalexample> - -<para> -(You can also disable Basic or Digest authentication by calling <link -linkend="soup-session-remove-feature-by-type"><function>soup_session_remove_feature_by_type</function></link> -on <link linkend="SOUP-TYPE-AUTH-BASIC:CAPS"><literal>SOUP_TYPE_AUTH_BASIC</literal></link> -or <link linkend="SOUP-TYPE-AUTH-DIGEST:CAPS"><literal>SOUP_TYPE_AUTH_DIGEST</literal></link>.) -</para> - -</refsect2> - -<refsect2> -<title>Multi-threaded usage</title> - -<para> -A <link linkend="SoupSession"><type>SoupSession</type></link> can be -used from multiple threads. However, if you are using the async APIs, -then each thread you use the session from must have its own -thread-default <link linkend="GMainContext"><type>GMainContext</type></link>. -</para> - -<para> -<link linkend="SoupMessage"><type>SoupMessage</type></link> is -<emphasis>not</emphasis> thread-safe, so once you send a message on -the session, you must not interact with it from any thread other than -the one where it was sent. -</para> - -</refsect2> - -<refsect2> -<title>Sample Programs</title> - -<para> -A few sample programs are available in the -<application>libsoup</application> sources, in the -<literal>examples</literal> directory: -</para> - -<itemizedlist> - <listitem><para> - <emphasis role="bold"><literal>get</literal></emphasis> is a simple command-line - HTTP GET utility using the asynchronous API. - </para></listitem> - - <listitem><para> - <emphasis role="bold"><literal>simple-proxy</literal></emphasis> uses both the - client and server APIs to create a simple (and not very - RFC-compliant) proxy server. - </para></listitem> -</itemizedlist> - -<para> -More complicated examples are available in GNOME git. -</para> - -</refsect2> - -</refentry> diff --git a/docs/reference/gtk-markdown-to-docbook.py b/docs/reference/gtk-markdown-to-docbook.py new file mode 100755 index 00000000..25274116 --- /dev/null +++ b/docs/reference/gtk-markdown-to-docbook.py @@ -0,0 +1,201 @@ +#!/usr/bin/python3 +# +# Call pandoc to convert markdown to docbook, then expand gtk-doc +# abbreviations (|[ ]|, function(), #object, %constant, etc) + +# Upstream: https://gitlab.gnome.org/GNOME/gtk/-/blob/master/docs/reference/gtk/gtk-markdown-to-docbook + +import sys +import re +import tempfile +import os.path +import subprocess + +# The following code is taken from gtk-doc + +def ExpandAbbreviations(symbol, text): + # Hack! + # Strip xlink namespace from hrefs since pandoc insists on + # inserting them, and namespace setup doesn't transfer across + # xi:include. + # Yay for XML! + text = re.sub('xlink:href', 'href', text) + + # Convert '@param()' + text = re.sub(r'(\A|[^\\])\@(\w+((\.|->)\w+)*)\s*\(\)', r'\1<parameter>\2()</parameter>', text) + + # Convert 'function()' or 'macro()'. + # if there is abc_*_def() we don't want to make a link to _def() + # FIXME: also handle abc(def(....)) : but that would need to be done recursively :/ + def f1(m): + return m.group(1) + MakeXRef(m.group(2), tagify(m.group(2) + "()", "function")) + text = re.sub(r'([^\*.\w])(\w+)\s*\(\)', f1, text) + # handle #Object.func() + text = re.sub(r'(\A|[^\\])#([\w\-:\.]+[\w]+)\s*\(\)', f1, text) + + # Convert '@param', but not '\@param'. + text = re.sub(r'(\A|[^\\])\@(\w+((\.|->)\w+)*)', r'\1<parameter>\2</parameter>', text) + text = re.sub(r'/\\\@', r'\@', text) + + # Convert '%constant', but not '\%constant'. + # Also allow negative numbers, e.g. %-1. + def f2(m): + return m.group(1) + MakeXRef(m.group(2), tagify(m.group(2), "literal")) + + text = re.sub(r'(\A|[^\\])\%(-?\w+)', f2, text) + text = re.sub(r'\\\%', r'\%', text) + + # Convert '#symbol', but not '\#symbol'. + + # Only convert #foo after a space to avoid interfering with + # fragment identifiers in urls + def f3(m): + return m.group(1) + MakeHashXRef(m.group(2), "type") + + text = re.sub(r'(\A|[ ])#([\w\-:\.]+[\w]+)', f3, text) + text = re.sub(r'\\#', '#', text) + + return text + +# Standard C preprocessor directives, which we ignore for '#' abbreviations. +PreProcessorDirectives = { + 'assert', 'define', 'elif', 'else', 'endif', 'error', 'if', 'ifdef', 'ifndef', + 'include', 'line', 'pragma', 'unassert', 'undef', 'warning' +} + +def MakeHashXRef(symbol, tag): + text = symbol + + # Check for things like '#include', '#define', and skip them. + if symbol in PreProcessorDirectives: + return "#%s" % symbol + + # Get rid of special suffixes ('-struct','-enum'). + text = re.sub(r'-struct$', '', text) + text = re.sub(r'-enum$', '', text) + + # If the symbol is in the form "Object::signal", then change the symbol to + # "Object-signal" and use "signal" as the text. + if '::' in symbol: + o, s = symbol.split('::', 1) + symbol = '%s-%s' % (o, s) + text = u'“' + s + u'”' + + # If the symbol is in the form "Object:property", then change the symbol to + # "Object--property" and use "property" as the text. + if ':' in symbol: + o, p = symbol.split(':', 1) + symbol = '%s--%s' % (o, p) + text = u'“' + p + u'”' + + if tag != '': + text = tagify(text, tag) + + return MakeXRef(symbol, text) + +def MakeXRef(symbol, text=None): + """This returns a cross-reference link to the given symbol. + + Though it doesn't try to do this for a few standard C types that it knows + won't be in the documentation. + + Args: + symbol (str): the symbol to try to create a XRef to. + text (str): text to put inside the XRef, defaults to symbol + + Returns: + str: a docbook link + """ + symbol = symbol.strip() + if not text: + text = symbol + + # Get rid of special suffixes ('-struct','-enum'). + text = re.sub(r'-struct$', '', text) + text = re.sub(r'-enum$', '', text) + + if ' ' in symbol: + return text + + symbol_id = CreateValidSGMLID(symbol) + return "<link linkend=\"%s\">%s</link>" % (symbol_id, text) + +def CreateValidSGMLID(xml_id): + """Creates a valid SGML 'id' from the given string. + + According to http://www.w3.org/TR/html4/types.html#type-id "ID and NAME + tokens must begin with a letter ([A-Za-z]) and may be followed by any number + of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), + and periods (".")." + + When creating SGML IDS, we append ":CAPS" to all all-caps identifiers to + prevent name clashes (SGML ids are case-insensitive). (It basically never is + the case that mixed-case identifiers would collide.) + + Args: + id (str): The text to be converted into a valid SGML id. + + Returns: + str: The converted id. + """ + + # Special case, '_' would end up as '' so we use 'gettext-macro' instead. + if xml_id == '_': + return "gettext-macro" + + xml_id = re.sub(r'[,;]', '', xml_id) + xml_id = re.sub(r'[_ ]', '-', xml_id) + xml_id = re.sub(r'^-+', '', xml_id) + xml_id = xml_id.replace('::', '-') + xml_id = xml_id.replace(':', '--') + + # Append ":CAPS" to all all-caps identifiers + # FIXME: there are some inconsistencies here, we have index files containing e.g. TRUE--CAPS + if xml_id.isupper() and not xml_id.endswith('-CAPS'): + xml_id += ':CAPS' + + return xml_id + +def tagify(text, elem): + # Adds a tag around some text. + # e.g tagify("Text", "literal") => "<literal>Text</literal>". + return '<' + elem + '>' + text + '</' + elem + '>' + +# End of gtk-doc excerpts + +MarkdownExtensions = { + '-auto_identifiers', # we use explicit identifiers where needed + '+header_attributes', # for explicit identifiers + '+blank_before_header', # helps with gtk-doc #Object abbreviations + '+compact_definition_lists', # to replace <variablelist> + '+pipe_tables', + '+backtick_code_blocks', # to replace |[ ]| + '+fenced_code_attributes', # to add language annotations + '-raw_html', # to escape literal tags like <child> in input + '+startnum', # to have interrupted lists in the q&a part +} + +def ConvertToDocbook(infile, outfile): + basename = os.path.basename(infile) + if basename.startswith('section'): + division='section' + else: + division='chapter' + input_format = "markdown" + "".join(MarkdownExtensions) + output_format = "docbook4" + subprocess.check_call(["pandoc", infile, "-o", outfile, + "--from=" + input_format, + "--to=" + output_format, + "--top-level-division=" + division]) + +def ExpandGtkDocAbbreviations(infile, outfile): + contents = open(infile, 'r', encoding='utf-8').read() + with open(outfile, 'w', encoding='utf-8') as out: + out.write(ExpandAbbreviations("file", contents)) + + +if __name__ == '__main__': + tmp = tempfile.mktemp() + ConvertToDocbook(sys.argv[1], tmp) + ExpandGtkDocAbbreviations(tmp, sys.argv[2]) + os.remove(tmp) diff --git a/docs/reference/meson.build b/docs/reference/meson.build index a7463352..f528bedd 100644 --- a/docs/reference/meson.build +++ b/docs/reference/meson.build @@ -1,3 +1,5 @@ +fs = import('fs') + ignore_headers = [ 'gconstructor.h', 'soup.h', @@ -48,6 +50,31 @@ scan_args = [ glib_prefix = glib_dep.get_pkgconfig_variable('prefix') glib_docpath = glib_prefix / 'share' / 'gtk-doc' / 'html' +content_files = [ + 'build-howto.xml', + 'server-howto.xml', +] + +expand_content_md_files = [ + 'client-howto.md', +] + +# Needed for gtk-markdown-to-docbook.py +pandoc = find_program('pandoc', required: true) +expand_md = find_program('gtk-markdown-to-docbook.py') +expand_md_targets = [] +foreach t : expand_content_md_files + content_files += custom_target(t, + input : [ t ], + output : [ fs.replace_suffix(t, '.xml') ], + command : [ expand_md, '@INPUT@', '@OUTPUT@'], + # At least in meson 0.55.3 this target wouldn't build even though its + # listed in the content_files + build_by_default : true, + ) +endforeach + + gnome.gtkdoc('libsoup-3.0', main_xml : 'libsoup-3.0-docs.xml', src_dir : srcdir, @@ -63,9 +90,5 @@ gnome.gtkdoc('libsoup-3.0', ], dependencies : libsoup_dep, install : true, - content_files: [ - 'build-howto.xml', - 'client-howto.xml', - 'server-howto.xml' - ] + content_files : content_files, ) |