Skip to content
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

printing with :hardcopy should respect folds #4099

Open
jm3 opened this issue Mar 11, 2019 · 14 comments

Comments

Projects
None yet
5 participants
@jm3
Copy link

commented Mar 11, 2019

Per @masukomi's comment on vim-markdown-folding's #23 and @ychin's note on macvim-dev' #874, printing in vim uses :hardcopy, which ignores folding. This decision has unfortunate consequences, in that it results in unfortunate surprises for users who print and fold.

Following the UI principle of Least Surprise, printed output for folded documents should respect respect content hidden by folds (otherwise the screen and printed output will differ wildly), and certain forms of documents will be unprintable, e.g. a collapsed outline. In a perfect world, printing would respect the folded state of the buffer. In an imperfect, but improved world, perhaps a warning could be displayed when printing that all folds will be unfolded in the printed output, at least until this can be updated?

Currently, unless this is changed, a folded document on screen:

1. Thing 1
...
2. Thing 2
...

will print in a completely unexpected and different fashion, like this:

 1. Thing 1

  __        ___   ___   __  ___   __  __ _   _ ____ _____
  \ \      / / | | \ \ / / |_ _| |  \/  | | | / ___|_   _|
   \ \ /\ / /| |_| |\ V /   | |  | |\/| | | | \___ \ | |
    \ V  V / |  _  | | |    | |  | |  | | |_| |___) || |
     \_/\_/  |_| |_| |_|   |___| |_|  |_|\___/|____/ |_|

  __        ______  ___ _____ _____    ____ _   _ _   _
  \ \      / /  _ \|_ _|_   _| ____|  / ___| \ | | | | |
   \ \ /\ / /| |_) || |  | | |  _|   | |  _|  \| | | | |
    \ V  V / |  _ < | |  | | | |___  | |_| | |\  | |_| |
     \_/\_/  |_| \_\___| |_| |_____|  \____|_| \_|\___/


I consider that the Golden Rule requires that if I like a program I
must share it with other people who like it. Software sellers want
to divide the users and conquer them, making each user agree not to
share with others. I refuse to break solidarity with other users in
this way. I cannot in good conscience sign a nondisclosure agreement
or a software license agreement. For years I worked within the
Artificial Intelligence Lab to resist such tendencies and other
inhospitalities, but eventually they had gone too far: I could not
remain in an institution where such things are done for me against
my will.

2. Thing 2

So that I can continue to use computers without dishonor, I have
decided to put together a sufficient body of free software so that I
will be able to get along without any software that is not free. I
have resigned from the AI Lab to deny MIT any legal excuse to
prevent me from giving GNU away.(2)

Once GNU is written, everyone will be able to obtain good system
software free, just like air.(3)

This means much more than just saving everyone the price of a Unix
license. It means that much wasteful duplication of system
programming effort will be avoided. This effort can go instead into
advancing the state of the art.

Complete system sources will be available to everyone. As a result,
a user who needs changes in the system will always be free to make
them himself, or hire any available programmer or company to make
them for him. Users will no longer be at the mercy of one programmer
or company which owns the sources and is in sole position to make
changes.

Schools will be able to provide a much more educational environment
by encouraging all students to study and improve the system code.
Harvard's computer lab used to have the policy that no program could
be installed on the system if its sources were not on public
display, and upheld it by actually refusing to install certain
programs. I was very much inspired by this.

Finally, the overhead of considering who owns the system software
and what one is or is not entitled to do with it will be lifted.

Arrangements to make people pay for using a program, including
licensing of copies, always incur a tremendous cost to society
through the cumbersome mechanisms necessary to figure out how much
(that is, which programs) a person must pay for. And only a police
state can force everyone to obey them. Consider a space station
where air must be manufactured at great cost: charging each breather
per liter of air may be fair, but wearing the metered gas mask all
day and all night is intolerable even if everyone can afford to pay
the air bill. And the TV cameras everywhere to see if you ever take
the mask off are outrageous. It's better to support the air plant
with a head tax and chuck the masks.
@dylnmc

This comment has been minimized.

Copy link

commented Mar 29, 2019

@jm3 one option is to write a quick function to convert the viewable lines to the printed lines. What you're asking for is, in my opinion, out of vim's scope, but it can be scripted. (The reason I say this is because vim edits plain text documents, and when you use hardcopy, vim minimally touches up the document so it will fit on the screen, but it won't jump through a thousand hoops to properly print things that are concealed of folded, for instance - among the many other hoops it perhaps could jump through; indeed, if you want to have more control over how things are printed, then you should first create what you want to see and then print it via postscript or convert it to a pdf some other way, since these options are more powerful and designed for this purpose.) Please see the example below - which will open a new window at the bottom and contain only the viewable lines including the 'foldtext' for lines that are folded. (Note: there is probably a vim 8.1 or vim 8.0 minimum requirement given the functions I used.)

function! PrintBuffer()
	let l:curpos = getcurpos()
	let l:bufnr = bufnr('%')
	let l:ft = &ft
	let l:linenr = line('$')
	call setpos('.', [l:bufnr, 1, 1, 0])
	let l:lines = []
	let l:line = 1
	let l:FoldText = function(empty(&foldtext) ? 'foldtext' : substitute(&foldtext, '\s*(\s*)\s*$', '', ''), [])
	while l:line < l:linenr
		let l:foldend = foldclosedend('.')
		if l:foldend ==# -1
			call add(l:lines, getline('.'))
		else
			call add(l:lines, l:FoldText())
		endif
		let l:line += abs(l:foldend)
		call setpos('.', [l:bufnr, l:line, 1, 0])
	endwhile
	call setpos('.', l:curpos)
	belowright new
	call setline(1, l:lines)
	let &ft = l:ft
	setlocal nofoldenable
endfunction
command -nargs=0 -bar PrintBuffer call PrintBuffer()

If you feel this has satisfactorily answered your question, please close the issue; if you do not feel that is the case, please leave it open.

Cheers,
dylnmc

@jm3

This comment has been minimized.

Copy link
Author

commented Mar 30, 2019

Thanks, @dylnmc! I'm not sure I 100% understand the characterization that vim would have to "jump through a thousand hoops"; I'm saying, "vim should print the buffer in its current state" which is both the least surprising choice and also how printing works in every text editing app I know of. I get that vim is different but… that seems strange. :) But OK. Thanks!

@dylnmc

This comment has been minimized.

Copy link

commented Mar 31, 2019

I am not opposed to this, for what it is worth, but this is what I am saying: when you send a range of lines to a command (for example, <line1>,<line2>write or, more usefully, '<,'>write), vim sends the plain text without any sort of modification to the command. That is how it is - in that regard, you're correct.

If you wanted to have what you describe, you'd have to create another option that perhaps takes a string so that it could be set to allow folds to be hidden with :hardcopy or :write as well as allow concealment to be written/hardcopy'd. This will require adding another option and writiing some C code. If Bram or some vim dev is up to the task, then great. The questions would then be: (1) how useful is this option when it can be scripted; (2) what commands should it apply to? just :hardcopy; (3) is this easily possible given how the code is written; (etc).

@masukomi

This comment has been minimized.

Copy link

commented Apr 2, 2019

I'm with @jm3 It's not clear what the "hoops" are @dylnmc . I say this from a perspective of ignorance not disagreement.

From an outsider's perspective it seems confusing that vim appears to have a clue what lines are folded and which aren't and thus you'd think the function would be something along the lines of

  • process file as if for display on infinitely tall screen with the desired print width
  • take that text and send it to the existing hardcopy function.

What are we missing? Is it something to do with the syntax highlighting?

@ychin

This comment has been minimized.

Copy link

commented Apr 3, 2019

The issue is that as mentioned by @dylnmc, :hardcopy basically just takes a range of lines from the file and use that to create the Postscript file to print out or convert to PDF etc. It doesn’t contain any formatting information or metadata.

To see this in practice, write a long line, then call :hardcopy with or without :set wrap. The results would be the same as that’s more a display / formatting information. On the other hand, if you use :TOhtml the difference would be captured.

Now, obviously Vim knows what lines are folded so it’s possible to include that info, but this would basically be a new feature to integrate folds and other displays / formatting info to print that out. It’s up to Bram to decide but I would imagine just like most feature requests it’s about time management and what feature to implement and whatnot.

I have already recommended on the MacVim thread but does using :TOhtml and then printing the results not suffice?

@masukomi

This comment has been minimized.

Copy link

commented Apr 3, 2019

I have already recommended on the MacVim thread but does using :TOhtml and then printing the results not suffice? - @ychin

first off "using :TOhtml" really means

  • run :TOhtml
  • save resulting file
  • open file in browser
  • go to print dialog
  • probably undo them random crap your browser wants to add to the printed verison of the page
  • accept the horrible fact that it's going to wrap badly
  • print
  • switch to terminal / finder / run terminal command in vim
  • delete file you didn't want in the first place
  • switch to vim

Not only is the wrapping a non-trivial issue it's a convoluted pain in the butt that relies on external apps and prays they won't screw it up (but they do anyway). It's not even remotely equivalent to printing anywhere else. Vim, printers, and PDFs have been around for enough years that this is long overdue. Emacs has had this for how many years now?

The suggestion to use :TOhtml is like suggesting someone walk the 30 miles to work instead of driving. Sure you can do it, but it's a pain in the butt that takes longer and makes you not want to work at that place anymore.

Note that printing isn't just about outputting paper. It's one of the best available methods for sharing what you've created with the appropriate highlighting to people who aren't using vim. emailing / slacking / file sharing HTML files is not really a commonly understood / accepted way to share files these days. I, for example, use printing to generate PDFs of ideas I want to discuss / share with coworkers when we can't be in the same room sharing a screen together. It sucks when i have to delete most of the file just to do that.

@dylnmc

This comment has been minimized.

Copy link

commented Apr 3, 2019

The proof is in the pudding: I've already written a (blazingly fast) function that does that which is desired. It's like walking 5 minutes to work rather than developing complex flying car just so you can get to work in 3 minutes. @masukomi

@masukomi

This comment has been minimized.

Copy link

commented Apr 3, 2019

@dylnmc I'm sorry to report that there are actually quite a few bugs in your function. HOWEVER Assuming it's actually possible to debug and make it do the right thing (including correct syntax highlighting) why wouldn't that be the solution to this problem? Take the output of the function, shove it in a register, then run the print functionality on the contents of the register... I'm just thinking off the top of my head here.

On the one hand you keep saying that it's a very hard thing, but on the other you're like "here's a function that gets you 90% of the way there [ignoring the bugs]". It's still not clear what makes this request so hard. If someone could explain the complexity of the request to us outsiders (at a high level) we might be able to put our heads together and come up with a solution. So far it seems achievable.


buggy PrintBuffer results

Source:

#     Markdown example                        [2 lines]---
## Formatting examples
###   Italic                                  [2 lines]---
###   Backtick handling                       [2 lines]---
###   Blockquote Handling                     [2 lines]---
## List Handling
### Bullet Lists

* bullet lists
* have highlighted asterisks
* another item with many words that will
  wrap shortly but alas will not wrap a
  second time

###   Ordered Lists                           [5 lines]---

PrintBuffer output:

###   Ordered Lists                           [5 lines]
## Formatting examples
###   Ordered Lists                           [5 lines]
###   Ordered Lists                           [5 lines]
###   Ordered Lists                           [5 lines]
@masukomi

This comment has been minimized.

Copy link

commented Apr 3, 2019

just tested the PrintBuffer funciton out with some ruby code and sections of unfolded code are missing completely and and an UNfolded method (def claim_bounty(bounty) ) had this appended above the comment preceding it +- 8 lines: def claim_bounty(bounty) and repeated twice below it also none of the code below the bottom of the visible screen was included. So yeah, still far from a usable solution right now.

@dylnmc

This comment has been minimized.

Copy link

commented Apr 3, 2019

yep. I hadn't tested PrintBuffer() function. It's unfortunately a bad solution because of how foldtext functions work; there might be another small bug also, unfortunately. It would be easiest to make a dummy foldtext() function and to allow your current function that you set 'foldtext' to to allow for an optional paremeter (you'd have to check if a:000 > 0, though). But you're correct in that my solution was tested very minimally and does not work well. It could be modified to work, perhaps, with some additional effort.

The reason it is not easy to just modify the vim source code to fix this is because commands already receive the raw lines without any filtering. In order to implement this filtering in the vim source code, you would have to rewrite how output is piped to all commands while preserving the way it is already done (since for most commands you'd want to send the raw output) with another option or some way to indicate that you want this filtering to occur. This is why I thought it would be easier to create the output you want to see before running :hardcopy.

@chrisbra

This comment has been minimized.

Copy link
Member

commented Apr 3, 2019

Yes, printing using :hardcopy basically only prints the whole buffer content, without taking into account the visual appearance. The current work-around is to use the :TOhtml command and printing from the browser.
Enhancing the printing function has been a long whish of users, however considering the length of the todo list, it might take a while until this will be developed (unless someone steps up and provides patches with a test).

@chrisbra chrisbra added the enhancement label Apr 3, 2019

@ychin

This comment has been minimized.

Copy link

commented Apr 4, 2019

I was suggesting the :TOhtml method because it works today. I would imagine the original requester is interested in getting stuff done now rather than waiting for a feature to be implemented in the future. As explained already by multiple people, getting this feature working perfectly requires some thought and isn't trivial to implement. Since hardcopy doesn't know anything about visual data, you now have to pipe a lot more data and think about how to send the display data over, how layout would work, etc, so it's essentially a new feature.

(@masukomi)

first off "using :TOhtml" really means

run :TOhtml
save resulting file
open file in browser
go to print dialog
probably undo them random crap your browser wants to add to the printed verison of the page
accept the horrible fact that it's going to wrap badly
print
switch to terminal / finder / run terminal command in vim
delete file you didn't want in the first place
switch to vim

Note that Vim's :hardcopy feature works by generating a temporary .ps file too which you then have to manually convert to a pdf file or whatnot before printing. In fact, in MacVim (the original issue was filed against it) it doesn't even open a print dialog box. It generates the ps file, then open it in Preview which you have to print manually.

Also, most of the steps you mentioned could be automated if you are willing to script together a function (or have a plugin do it) and you could also use tools like wkhtmltopdf to generate pdfs for printing without needing a browser. No one is saying this is perfect but it works. My point is that I think using or modifying TOhtml is a better starting point to get a working solution than implementing this from scratch in C code in Vim.

Also, wrapping should work in TOhtml. Did you try it and it didn't work for you?

emailing / slacking / file sharing HTML files is not really a commonly understood / accepted way to share files these days. I, for example, use printing to generate PDFs of ideas I want to discuss / share with coworkers when we can't be in the same room sharing a screen together. It sucks when i have to delete most of the file just to do that.

Honestly, generating an HTML file at least as an intermediary file is a much more versatile way IMO to handle this because it is resizable and are responsive (similar to a text editor). You could for example copy and paste from a HTML web page to an email or any document editors, and it's also much easier to export HTML document to PDF rather than vice versa.

Also, just a cursory glance shows that VSCode and Sublime Text also don't support printing natively, although there are plugins to do that. Xcode does do printing natively but it doesn't preserve folds similar to Vim as it's printing the document rather than the visual rep. Not sure about other text editors.

@masukomi

This comment has been minimized.

Copy link

commented Apr 9, 2019

Also, wrapping should work in TOhtml. Did you try it and it didn't work for you? - @ychin

Yes I tried it, but no it doesn't quite work. The HTML generated does appear to have the appropriate wrapping, BUT then you have to deal with the browser thinking "you know, this line is too long for printing. I'm gonna wrap it early." So you have full line, line with 2 "words", full line, line with 1 "word", etc. It's probably not so noticeable when printing code as it is when printing prose.

This is why the problem needs to be addressed within Vim. Opening in Preview (or local equivalent) for printing (as MacVim) does is acceptable, because it's a postscript file which means nothing should be mucking with it before sending it to the printer. Yes it's an additional step but it's a step that doesn't impose its own opinions and modifications before sending it to the printer.

@ychin

This comment has been minimized.

Copy link

commented Apr 9, 2019

From guessing based on your descriptions, you need to make sure you don’t both wrap your text using textwidth (hard wrap) and wrap (soft wrap). I don’t think there’s an easy solution for that if that’s what’s happening. Easiest way is joining all the hard-wrapped lines using J and then rely on soft wrapping.

The thing is a text file is inherently formatless. Someone has to make a decision how to format a file to a fixed width on a page, either Vim or the web browser. If done in Vim it would likely mean implementing a whole layout engine for printing. HTML is a really robust standard by now so I feel like there’s either a bug or how you are wrapping the text that’s the issue here. Do you have an example? I’m curious to see.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.