-
-
Notifications
You must be signed in to change notification settings - Fork 167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Contributing a new Lua filter for Font styling and alignment #218
Comments
Thanks for this, that's a nice little filter. Below are a few small suggestions.
Keeping everything in a single file seems like a good choice at this moment. Hope this is helpful. |
This is very similar to a filter which I posted to the Pandoc mailing list recently https://v.gd/GQL7mL. You might want to look at how I did things. In particular:
local abbrev = {
bold = 'bf',
italic = 'it',
serif = 'rm',
smallcaps = 'sc',
sans = 'sf',
slanted = 'sl',
monospace = 'tt',
}
for _,style in pairs(LATEX_CODE_FOR_TAGS) do
for long, short in pairs(abbrev) do
style[short] = style[long]
end
end
I would as you see create the RawInline and RawBlock objects only once during initialization and reuse them to save resources, unless @tarleb thinks that that may have adverse effects: end_span = pandoc.RawInline('latex', '}')
local span = LATEX_CODES.Span
for class,code in pairs(span) do
code = pandoc.RawInline(code)
span[class] = { code, end_span }
end
local div = LATEX_CODES.Div
for class,code1 in pairs(div) do
local code2 = code1:gsub('begin','end')
div[class] = {
pandoc.RawBlock('latex', code1),
pandoc.RawBlock('latex', code2),
}
end
local function handler (elem)
local style = LATEX_CODES[elem.tag]
-- Unpack the stuff we need
local class = elem.classes
local content = elem.content
-- Looping over the classes in the element is more efficient!
-- And we loop backwards so the commands come in the same order as the classes!
for i=#class,1,-1 do
if style[class[i]] then
-- The content is a pandoc.List object
content:insert(1, style[class][1])
content:insert(style[class][2])
end
end
elem.content = content
return elem
end
Span = handler
Div = handler I hope this helps! |
@tarleb and @bpj thank you for your valuable comments. @bpj I was using the code you posted on Pandoc discuss as a base as you were answering my question. I value the opportunity to collaborate with both of you on this filter. I will take up your suggestions and message you both once I am done. I hope you won't mind giving me another review later. |
I have made improvements to the filter according to your suggestions above.
What I have not done are the following:
If the two of you don't mind giving my code another review I would appreciate it. My main concern now is the maintainability of the LATEX_CODE_FOR_TAGS table. If I was using a language I am familiar with I would have broken it up into three tables. In Lua, I find that I would have to loop through three tables to find the correct class which I want to avoid as merging tables is a little involved. In addition, I am open to suggestions for a better name for the filter that is more descriptive. Thanks in advance. |
Nice, looks good to me! I agree that the local latex_font_sizes = {
xxsmall = 'scriptsize',
xsmall = 'footnotesize',
-- ...
}
for k, v in pairs(latex_font_sizes) do
LATEX_CODES_FOR_TAGS.Span[k] = {'\\'.. v .. ' ', '}'}
LATEX_CODES_FOR_TAGS.Div[k] = {'\\begin{'.. v .. '}', '\\end{' .. v .. '}'}
end |
Thanks, @tarleb for the code above, but considering the fact that the code is not the same for inlines and divs for LaTeX it might not be worth the work. I think I might end up with something even more unwieldy. So perhaps I should leave the code as it is right now. I am now facing an issue where the expected output and the generated output do not match. This only seems to occur when I specify more than one style for a piece of text for example:
The classes when accessed in the code do not seem to follow a set order as far as I can tell. Because the classes get applied in a different order each time the corresponding LaTeX code also gets applied in a different order, and as a result, the expected and actual do not match. Is there a way to preserve the order of the classes and not have it change every time? I thought that because the I hope you will be able to enlighten me on why this is the case and what would be a good workaround. |
The reason for the non-determinism is that The easiest would be to iterate over the |
Aside: we do guarantee a certain order when using |
Thanks, @tarleb the first method works but I need some explanation on how iterating over I think I am missing something here conceptually and would like to understand the mechanism being used here. I have uploaded the new code to the repository. |
The |
Ah @tarleb that makes much more sense now. I have changed What would be the next steps now? |
We still haven't decided how to deal with new filters in this repo. You could announce the new filter on the pandoc-discuss mailing list, so others can start to use it. |
@tarleb Before I announced the filter I wanted to make the change regarding separating the large style list into three and I am happy to say that I have succeeded in that endeavor. I am now happy with the filter code and would like to request one more review of the code. I have a question about the "magical" |
Sorry, I currently don't have time for another detailed review. |
(I wrote this on Sunday but for some reason never got around to posting it. Anyway here it is...) You really should loop through the classes of
Consider for example this span:
If you loop through the classes in forward order the LaTeX code looks like this, with the commands in the opposite order to the classes in the markdown: {\textsc{\textbf{\textsf{foo}}}} If you loop through the {\textsf{\textbf{\textsc{foo}}}} but if you loop through The reverse Therefore you should replace line 93 through 102 with the following: local class = elem.classes
for i=#class, 1, -1 do
if code_for_class[class[i]] then
local begin_code = code_for_class[class[i]][1]
local end_code = code_for_class[class[i]][2]
table.insert(elem.content, 1, raw('latex', begin_code))
if end_code then
table.insert(elem.content, raw('latex', end_code))
end
end
end Of course the assignment of You might want to include the full gamut of LaTeX font style commands, since if some of them are available people will expect all of them to be available:
As for the ulem commands why not include them but comment them out so that users who load ulem unconditionally in a custom LaTeX template can just uncomment them if they wish? |
I'll try to find time to do a review later today. |
Thanks, @bpj for your review. With the latest version of the code, I am looping through The code has been modified quite a but now has fewer nested loops and uses table indexing where possible. I am happy to add the underline style if there is a way for me to check if the As for enabling the other styles the one that I am most concerned about is I will try and incorporate the others. |
@bpj I have added some of the styles but not all because I do not wish to add support for capabilities Pandoc Markdown already provides such as The LIght font feature is non-standard and slanted is not too different from italic so I have made a value judgment on what might be useful. I have added medium and normal fonts though. I have uploaded the changes to GitHub so they can be reviewed |
First: this can work for Links as well as for Spans just by saying latex_cmd_for_tags.Link = latex_cmd_for_tags.Span At least in my opinion the first of these looks better than the second, and is probably more efficient in Pandoc:
You could inject the So here is some code which will do the injects if a metadata field is set to an appropriate value ("true", "yes" or -- Save some typing and check that we got the pandoc libraries
local p = assert(pandoc, "Cannot find the pandoc library")
if not ('table' == type(p)) then
error("Expected variable pandoc to be table")
end
local u = assert(pandoc.utils, "Cannot find the pandoc.urils library")
local L = assert(pandoc.List, "Cannot get the pandoc.List class")
-- Stringify safely
local function stringify (val, accept_bool)
-- First try
local ok, res = pcall(u.stringify, val)
if ok and res then
return res
end
local vt = u.type(val)
if ('string' == vt) or ('number' == vt) or (accept_bool and ('boolean' == vt)) then
return tostring(val)
else
return error("Cannot stringify " .. vt)
end
end
-- Convert appropriate values in meta or env to boolean
local bool_for = {
["true"] = true, -- string to bool
["false"] = false,
yes = true
no = false
}
local function boolify (val)
str = stringify(val, true):lower() -- case insensitive
return bool_for[str]
end
-- Let the user request the ulem styles through metadata or environment
local function Meta (meta)
-- Check if we have a meta value
local want_ulem = meta.ulem_styles
-- If not try the environment variable
if nil == want_ulem then
-- The environment variable is either unset or a string
-- Default to a false boolean if unset
want_ulem = os.getenv("PANDOC_ULEM_STYLES") or false
end
-- Try to "convert" it to a boolean
want_ulem = boolify(want_ulem)
-- Validate the result: if it was a boolean or an appropriate string
-- it is now a boolean. If not it is now a nil, and probably a mistake.
if nil == want_ulem then
error("Expected meta.ulem_styles or environment variable to be 'true', 'false' or unset")
end
-- If user wants it make sure we have a list of header-includes
if want_ulem then
-- Get header-includes if any
local includes = meta['header-includes']
-- Default to a List
includes = includes or L({ })
-- If not a List make it one!
if 'List' ~= u.type(includes) then
includes = L({ includes })
end
-- Add the ulem use statement
includes:insert(p.RawBlock('latex', "\\usepackage[normalem]{ulem}"))
-- Make sure Pandoc gets our changes
meta['header-includes'] = includes
---- Inject the ulem classes/commands into the main table ----
-- First we make a mapping from commands to the multiple classes for each command
local ulem_styles = {
["\\uline{"] = { "uline", "u" },
["\\uuline{"] = { "uuline", "uu" },
["\\uwave{"] = { "uwave", "uw" },
-- ["\\sout{"] = { "sout", "so" },
["\\xout{"] = { "xout", "xo" },
["\\dashuline{"] = { "dashuline", "da", "dau" },
["\\dotuline{"] = { "dotuline", "do", "dou" }
}
-- Inject them into the main table by looping through each command
-- and its classes and assign each command to all of its classes
for cmd, classes in pairs(ulem_styles) do
for _, class in ipairs(classes) do
latex_cmd_for_tags.Span[class] = { cmd, '}' }
end
end
-- Make sure Pandoc gets our changes
return meta
end
-- No request, do nothing
return nil
end
-- Run the metadata "filter" before the main filter by returning a list of
-- filters at the end of the file
return {
{ Meta = Meta },
{ Span = handler,
-- Link = handler,
Div = handler
}
} |
@bpj Thanks for the above. I will definitely look into incorporating the underline feature using the method you have suggested and see how far I get. I have added support for more style and font sizes as per your previous suggestions and updated the code. The only ones I am not adding are The others have been incorporated and are working well. I will get the underline things done and get in touch. |
@bpj @tarleb I have done my final commits for the filter code considering feature complete. I have allowed the I would appreciate one more code review before announcing the filter on pandoc-discuss. |
@tarleb Has there been any consensus reached on how Pandoc Lua filters will be managed in the future? I would like to contribute this filter publically if possible. |
Thank you for your patience @nandac. To be honest, I've put off writing an answer as I'm still not 100% sure about the best path. However, I currently strongly lean towards reducing the scope of this repo. Please publish the filter in a separate repository for the time being. Feel free to let us know when you published it: I'll then "advertise" it on social media. |
@tarleb Thank you for your reply. I have completed the work for the Lua filter for now and I know of at least one person who is using it in his projects. The repository is here: https://github.com/nandac/fonts-and-alignment The GitHub tests are not running now due to inactivity but the last commit passed all tests. I did announce it on Pandoc discuss a few months back. However, please feel free to advertise it on social media and hopefully, this filter can get more exposure. |
By the way, and completely off-topic: @nandac say hi for me to Jug and Magdalena at your place of work. I hope the math engine still does its job, I helped to build it. |
@tarleb I believe you are talking about Jugdip. He left the company about a month or two ago. I don't know Magdalena could you tell me her last name and I could say hi on your behalf. When did build the math engine? You have piqued my curiosity. By the way, do you have a LinkedIn page? I would like to connect. |
Sad to hear that Jugdip left. He did great work, and I'm a big fan his management style. I don't have LinkedIn, but I will send you an email! |
Dear Folks,
I would like to contribute a new Lua filter to the community that is available here: https://github.com/nandac/fonts-and-alignment
This filter currently only works for LaTeX documents, but I will be making it work for HTML and ePub in the future.
As I am a beginner in Lua and LaTeX and would like to
I hope this would not be too much of an imposition on the community. The filter is not very large at present.
The text was updated successfully, but these errors were encountered: