aboutsummaryrefslogtreecommitdiff
path: root/butl/pager
blob: 64a36ca66c28638b5552c928d099c931588c8f56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// file      : butl/pager -*- C++ -*-
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef BUTL_PAGER
#define BUTL_PAGER

#include <string>
#include <vector>
#include <iostream>

#include <butl/export>

#include <butl/process>
#include <butl/fdstream>

namespace butl
{
  // Try to run the output through a pager program, such as more or less (no
  // pun intended, less is used by default). If the default pager program is
  // used, then the output is indented so that 80-character long lines will
  // appear centered in the terminal. If the default pager program fails to
  // start, then the output is sent directly to STDOUT.
  //
  // If the pager program is specified and is empty, then no pager is used
  // and the output is sent directly to STDOUT.
  //
  // Throw std::system_error if there are problems with the pager program.
  //
  // Typical usage:
  //
  // try
  // {
  //   pager p ("help for foo");
  //   ostream& os (p.stream ());
  //
  //   os << "Foo is such and so ...";
  //
  //   if (!p.wait ())
  //     ... // Pager program returned non-zero status.
  // }
  // catch (const std::system_error& e)
  // {
  //   cerr << "pager error: " << e.what () << endl;
  // }
  //
  class LIBBUTL_EXPORT pager: protected std::streambuf
  {
  public:
    ~pager () {wait (true);}

    // If verbose is true, then print (to STDERR) the pager command line.
    //
    pager (const std::string& name,
           bool verbose = false,
           const std::string* pager = nullptr,
           const std::vector<std::string>* pager_options = nullptr);

    std::ostream&
    stream () {return os_.is_open () ? os_ : std::cout;}

    bool
    wait (bool ignore_errors = false);

    // The streambuf output interface that implements indentation. You can
    // override it to implement custom output pre-processing.
    //
  protected:
    using int_type = std::streambuf::int_type;
    using traits_type = std::streambuf::traits_type;

    virtual int_type
    overflow (int_type);

    virtual int
    sync ();

  private:
    process p_;
    ofdstream os_;

    std::string indent_;
    int_type prev_ = '\n'; // Previous character.
    std::streambuf* buf_ = nullptr;
  };
};

#endif // BUTL_PAGER