tabulo 2.7.3 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d0744fe4dfb79a4a05cf2f7c0e2222c3364dfc907897ed7f1d304f9b2702ba9
4
- data.tar.gz: 9008fd0d0ce6a4df33650bfd317030d5ed36aede411cb476f0d2774352b87b8a
3
+ metadata.gz: d58a5b883e9c9685c3cff492c6ad49b88ce921c5947596c5fe9199a5818dbfab
4
+ data.tar.gz: d9e2d10ea6314b73bdc3ad5a41bf790211ad7abe1e42899c52bc8bf2b405e8e6
5
5
  SHA512:
6
- metadata.gz: a076fadf6d1fcb905f52c735396bdbed69b03718ca8bac21fa25d2f6c64f16e5b20b196b9f0d16d73b34b9d25b71abac6485fe68bbc733d7474348f84f6dc768
7
- data.tar.gz: 72a96aa1c8d9152d95a77a98cd0478701cfd97d56fed4da51534d199bc7165f255b0001accea4bc9602d67291cd5725d0c2db03043e1e1f742014985ea183f97
6
+ metadata.gz: 3fb526cb0ddc9d63033eb40aa81a0aa2f39a306e051074693fcc4d08c95a216d13ffa27c92a1eb7bed08d3daef431bff6d15faa839b87580f830b916409c46a7
7
+ data.tar.gz: 587ba915a07b2e6d67d58296a7147fab9017d038facf0976a628baa71f8ebdf6a08f3d25559ca372630026452d65d12f83ced616c78cd33fca9e7e31ff0ed597
@@ -26,6 +26,7 @@ jobs:
26
26
  '2.6.9',
27
27
  '2.7.5',
28
28
  '3.0.3',
29
+ '3.1.0',
29
30
  ]
30
31
  steps:
31
32
  - uses: actions/checkout@v2
data/CHANGELOG.md CHANGED
@@ -1,8 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ### v2.8.0
4
+
5
+ * Add `except:` param to `Tabulo::Table#pack` method, allowing specific
6
+ columns to be excluded from the action of `.pack`
7
+ * Provide method `Tabulo::Table#autosize_columns`, allowing columns to be auto-sized
8
+ to fit their contents' widths, without having to call `.pack` (which also has
9
+ other effects on the table). This method also has an `except:` param allowing columns
10
+ to be excluded from its action.
11
+ * Provide method `Tabulo::Table#shrink_to`, allowing the table's width to be reduced
12
+ so as not to exceed a given target number of characters (or the argument `:screen`
13
+ meaning "width of terminal"), independently of the `.pack` method.
14
+ This method also has an `except:` param allowing columns to be excluded from its action.
15
+ * Fix `max_table_width:` param to `.pack` not being respected if table title was
16
+ wider than terminal.
17
+ * Documentation improvements
18
+ * Fix broken documentation links
19
+ * Add Ruby 3.1 to CI config
20
+
3
21
  ### v2.7.3
4
22
 
5
- * Fix malformed YARD documentation for Tabulo::Table#initialize method
23
+ * Fix malformed YARD documentation for `Tabulo::Table#initialize` method
6
24
 
7
25
  ### v2.7.2
8
26
 
data/README.md CHANGED
@@ -74,13 +74,13 @@ Tabulo has also been ported to Crystal (with some modifications): see [Tablo](ht
74
74
 
75
75
  * [Overview](#overview)
76
76
  * [Features](#features)
77
- * [Table of contents](#table-of-contents)
77
+ * [Table of contents](#contents)
78
78
  * [Installation](#installation)
79
79
  * [Detailed usage](#detailed-usage)
80
80
  * [Creating a table](#table-initialization)
81
81
  * [Adding columns](#adding-columns)
82
82
  * [Quick API](#quick-api)
83
- * [Full API](#quick-api)
83
+ * [Full API](#full-api)
84
84
  * [Column labels _vs_ headers](#labels-headers)
85
85
  * [Positioning columns](#column-positioning)
86
86
  * [Extracting column content from a hash or array](#from-arrays-hashes)
@@ -113,6 +113,7 @@ Tabulo has also been ported to Crystal (with some modifications): see [Tablo](ht
113
113
  * [Contributing](#contributing)
114
114
  * [License](#license)
115
115
 
116
+ <a name="installation"></a>
116
117
  ## Installation [&#x2191;](#contents)
117
118
 
118
119
  Add this line to your application&#8217;s Gemfile:
@@ -135,6 +136,7 @@ To use the gem, you need to require it in your source code as follows:
135
136
  require 'tabulo'
136
137
  ```
137
138
 
139
+ <a name="detailed-usage"></a>
138
140
  <a name="table-initialization"></a>
139
141
  ### Creating a table [&#x2191;](#contents)
140
142
 
@@ -408,9 +410,11 @@ If a table title is present, it is center-aligned by default. This can be change
408
410
  table = Tabulo::Table.new([1, 2], :itself, :even?, title: "Numbers", align_title: :left)
409
411
  ```
410
412
 
413
+ <a name="column-width-wrapping-and-truncation"></a>
411
414
  ### Column width, wrapping and truncation [&#x2191;](#contents)
412
415
 
413
416
  <a name="fixed-column-widths"></a>
417
+ <a name="configuring-fixed-widths"></a>
414
418
  #### Configuring fixed widths [&#x2191;](#contents)
415
419
 
416
420
  By default, column width is fixed at 12 characters, plus 1 character of padding on either side.
@@ -453,6 +457,7 @@ table = Tabulo::Table.new([1, 2], :itself, :even?, column_width: 6)
453
457
  Widths set for individual columns always override the default column width for the table.
454
458
 
455
459
  <a name="pack"></a>
460
+ <a name="automating-column-widths"></a>
456
461
  #### Automating column widths [&#x2191;](#contents)
457
462
 
458
463
  Instead of setting column widths &ldquo;manually&rdquo;, you can tell the table to sort out the widths
@@ -529,6 +534,16 @@ necessary (see [Overflow handling](#overflow-handling)). Under the hood, a chara
529
534
  is deducted column by column&mdash;the widest column being targetted each time&mdash;until
530
535
  the table will fit.
531
536
 
537
+ To resize only specific columns, `pack` takes an `except:` argument, which can be a single column
538
+ label or an Array of column labels. E.g. `pack(except: :id)` will exclude the `id` column from
539
+ resizing and let it keep its current width. This is useful if you want to prevent the addition of
540
+ linebreaks in your data. When using this option, other columns might be shrunk more to still make
541
+ the table fit within the `max_table_width`.
542
+
543
+ For even finer-grained control over column and table resizing, see the
544
+ for the [`#autosize_columns`](https://www.rubydoc.info/gems/tabulo/2.8.0/Tabulo/Table#autosize_columns-instance_method)
545
+ and [`#shrink_to`](https://www.rubydoc.info/gems/tabulo/2.8.0/Tabulo/Table#autosize_columns-instance_method) methods.
546
+
532
547
  Note that `pack`ing the table necessarily involves traversing the entire collection up front as
533
548
  the maximum cell width needs to be calculated for each column. You may not want to do this
534
549
  if the collection is very large.
@@ -792,7 +807,7 @@ the table.
792
807
  The `formatter` callback also has an alternative, 2-parameter version. If `formatter` is passed
793
808
  a 2-parameter callable, the second parameter will be given a `CellData` instance,
794
809
  containing additional information about the cell that may be useful in determining how to format
795
- it&mdash;see the [documentation](https://www.rubydoc.info/gems/tabulo/2.7.3/Tabulo/CellData.html)
810
+ it&mdash;see the [documentation](https://www.rubydoc.info/gems/tabulo/2.8.0/Tabulo/CellData.html)
796
811
  for details.
797
812
 
798
813
  <a name="colours-and-styling"></a>
@@ -838,7 +853,7 @@ number is even). The second parameter represents the formatted string value of t
838
853
  content after any processing by the [formatter](#formatting-cell-values). The third and fourth
839
854
  parameters are optional, and contain further information about the cell and its contents that may be useful in
840
855
  determining how to style it. See the
841
- [documentation](https://www.rubydoc.info/gems/tabulo/2.7.3/Tabulo/Table#add_column-instance_method) for details.
856
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.8.0/Tabulo/Table#add_column-instance_method) for details.
842
857
 
843
858
  If the content of a cell is wrapped over multiple lines, then the `styler` will be called once
844
859
  per line, so that each line of the cell will have the escape sequence applied to it separately
@@ -858,7 +873,7 @@ table.add_column(:even?, header_styler: -> (s) { "\033[32m#{s}\033[0m" })
858
873
  ```
859
874
 
860
875
  The `header_styler` option accepts a 1-, 2- or 3-parameter callable. See the
861
- [documentation](https://www.rubydoc.info/gems/tabulo/2.7.3/Tabulo/Table#add_column-instance_method)
876
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.8.0/Tabulo/Table#add_column-instance_method)
862
877
  for details.
863
878
 
864
879
  <a name="styling-title"></a>
@@ -872,7 +887,7 @@ table = Tabulo::Table.new(1..5, :itself, :even?, :odd?, title: "Numbers", title_
872
887
  ```
873
888
 
874
889
  The `title_styler` option accepts a 1- or 2-parameter callable. See the
875
- [documentation](https://www.rubydoc.info/gems/tabulo/2.7.3/Tabulo/Table#initialize-instance_method)
890
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.8.0/Tabulo/Table#initialize-instance_method)
876
891
  for details.
877
892
 
878
893
  <a name="styling-borders"></a>
@@ -1073,7 +1088,7 @@ a new table in which the rows and columns are swapped:
1073
1088
  By default, a header row is added to the new table, showing the string value of the element
1074
1089
  represented in that column. This can be configured, however, along with other aspects of
1075
1090
  `transpose`&#8217;s behaviour. For details, see the
1076
- [documentation](https://www.rubydoc.info/gems/tabulo/2.7.3/Tabulo/Table#transpose-instance_method).
1091
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.8.0/Tabulo/Table#transpose-instance_method).
1077
1092
 
1078
1093
  <a name="borders"></a>
1079
1094
  ### Configuring borders [&#x2191;](#contents)
@@ -1463,6 +1478,7 @@ install dependencies.
1463
1478
  `bundle exec rake spec` will run the test suite. For a list of other Rake tasks that are available in
1464
1479
  the development environment, run `bundle exec rake -T`.
1465
1480
 
1481
+ <a name="license"></a>
1466
1482
  ## License [&#x2191;](#contents)
1467
1483
 
1468
1484
  The gem is available as open source under the terms of the [MIT
@@ -1475,7 +1491,7 @@ License](http://opensource.org/licenses/MIT).
1475
1491
  [Awesome Ruby]: https://github.com/markets/awesome-ruby#cli-utilities
1476
1492
 
1477
1493
  [GV img]: https://img.shields.io/gem/v/tabulo.svg
1478
- [DC img]: https://img.shields.io/badge/documentation-v2.7.3-blue.svg
1494
+ [DC img]: https://img.shields.io/badge/documentation-v2.8.0-blue.svg
1479
1495
  [BS img]: https://github.com/matt-harvey/tabulo/actions/workflows/tests.yml/badge.svg
1480
1496
  [CS img]: https://img.shields.io/coveralls/matt-harvey/tabulo.svg
1481
1497
  [AR img]: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.7.3
1
+ 2.8.0
data/lib/tabulo/table.rb CHANGED
@@ -207,11 +207,10 @@ module Tabulo
207
207
  # by the Table-level setting passed to the <tt>align_header</tt> (which itself defaults
208
208
  # to <tt>:center</tt>). Otherwise, this option determines the alignment of the header
209
209
  # content for this column.
210
- # @param [Symbol, String, Integer, nil] before The label of the column before (i.e. to
211
- # the left of) which the new column should inserted. If <tt>nil</tt> is passed, it will be
212
- # inserted after all other columns. If there is no column with the given label, then an
213
- # {InvalidColumnLabelError} will be raised. A non-Integer labelled column can be identified
214
- # in either String or Symbol form for this purpose.
210
+ # @param [Symbol, Integer, nil] before The label of the column before (i.e. to the left of) which the
211
+ # new column should inserted. If <tt>nil</tt> is passed, it will be inserted after all other columns.
212
+ # If there is no column with the given label, then an {InvalidColumnLabelError} will be raised.
213
+ # A non-Integer labelled column can be identified in Symbol form for this purpose.
215
214
  # @param [#to_proc] formatter A lambda or other callable object that
216
215
  # will be passed the calculated value of each cell to determine how it should be displayed. This
217
216
  # is distinct from the extractor and the styler (see below).
@@ -453,8 +452,10 @@ module Tabulo
453
452
 
454
453
  # Resets all the column widths so that each column is *just* wide enough to accommodate
455
454
  # its header text as well as the formatted content of each its cells for the entire
456
- # collection, together with a single character of padding on either side of the column,
457
- # without any wrapping. In addition, if the table has a title but is not wide enough to
455
+ # collection, together with padding (by default 1 character on either side of the column),
456
+ # without wrapping. Other adjustments may also be performed (see below).
457
+ #
458
+ # In addition, if the table has a title but is not wide enough to
458
459
  # accommodate (without wrapping) the title text (with a character of padding either side),
459
460
  # widens the columns roughly evenly until the table as a whole is just wide enough to
460
461
  # accommodate the title text.
@@ -468,7 +469,7 @@ module Tabulo
468
469
  # is called. If the source Enumerable changes between that point, and the point when
469
470
  # the Table is printed, then columns will *not* be resized yet again on printing.
470
471
  #
471
- # @param [nil, Numeric] max_table_width With no args, or if passed <tt>:auto</tt>,
472
+ # @param [nil, :auto, Numeric] max_table_width With no args, or if passed <tt>:auto</tt>,
472
473
  # stops the total table width (including padding and borders) from expanding beyond the
473
474
  # bounds of the terminal screen.
474
475
  # If passed <tt>nil</tt>, the table width will not be capped.
@@ -476,34 +477,104 @@ module Tabulo
476
477
  # deducted from the width of the widest column until the target is reached. When the
477
478
  # table is printed, wrapping or truncation will then occur in these columns as required
478
479
  # (depending on how they were configured).
479
- # Note that regardless of the value passed to max_table_width, the table will always be left wide
480
- # enough to accommodate at least 1 character's width of content, 1 character of left padding and
481
- # 1 character of right padding in each column, together with border characters (1 on each side
482
- # of the table and 1 between adjacent columns). I.e. there is a certain width below width the
480
+ # Note that regardless of the value passed to `max_table_width`, the table will always be left wide
481
+ # enough to accommodate at least 1 character's width of content for each column, and the padding
482
+ # configured for each column (by default 1 character either side), together with border characters
483
+ # (1 on each side of the table and 1 between adjacent columns). I.e. there is a certain width below width the
483
484
  # Table will refuse to shrink itself.
485
+ # @param [nil, Symbol, Integer, Array[Symbol|Integer]] except If passed one or multiple column labels,
486
+ # these columns will be excluded from resizing and will keep their current width.
487
+ # (Note if passing integers, these are not necessarily positional: only columns _explicitly_
488
+ # given an integer label will have these as labels.)
484
489
  # @return [Table] the Table itself
485
- def pack(max_table_width: :auto)
486
- get_columns.each { |column| column.width = Util.wrapped_width(column.header) }
490
+ def pack(max_table_width: :auto, except: nil)
491
+ autosize_columns(except: except)
492
+
493
+ max_width = nil
494
+ if max_table_width
495
+ max_width = (max_table_width == :auto ? TTY::Screen.width : max_table_width)
496
+ shrink_to(max_width, except: except)
497
+ end
498
+
499
+ if @title
500
+ border_edge_width = (@border == :blank ? 0 : 2)
501
+ all_columns = get_columns
502
+ min_width =
503
+ Unicode::DisplayWidth.of(@title) +
504
+ all_columns.first.left_padding +
505
+ all_columns.last.right_padding +
506
+ border_edge_width
487
507
 
508
+ min_width = max_width if max_width && max_width < min_width
509
+ expand_to(min_width, except: except)
510
+ end
511
+
512
+ self
513
+ end
514
+
515
+ # Resets all the column widths so that each column is *just* wide enough to accommodate
516
+ # its header text as well as the formatted content of each its cells for the entire
517
+ # collection, together with padding (by default 1 character either side), without wrapping.
518
+ #
519
+ # @param [nil, Symbol, Integer, Array[Symbol|Integer]] except If passed one or multiple column labels,
520
+ # these columns will be excluded from resizing and will keep their current width.
521
+ # (Note if using integers, these are not necessarily positional: only columns _explicitly_
522
+ # given an integer label will have these as labels.)
523
+ # @return [Table] the Table itself
524
+ def autosize_columns(except: nil)
525
+ columns = get_columns(except: except)
526
+ columns.each { |column| column.width = Util.wrapped_width(column.header) }
488
527
  @sources.each_with_index do |source, row_index|
489
- get_columns.each_with_index do |column, column_index|
528
+ columns.each_with_index do |column, column_index|
490
529
  cell = column.body_cell(source, row_index: row_index, column_index: column_index)
491
530
  cell_width = Util.wrapped_width(cell.formatted_content)
492
531
  column.width = Util.max(column.width, cell_width)
493
532
  end
494
533
  end
534
+ self
535
+ end
495
536
 
496
- shrink_to(max_table_width == :auto ? TTY::Screen.width : max_table_width) if max_table_width
537
+ # If `max_table_width` is passed an integer, then column widths will be adjusted downward so
538
+ # that the total table width is reduced to the passed target width. (If the total width of the
539
+ # table exceeds the passed `max_table_width`, then this method is a no-op.)
540
+ #
541
+ # Width is deducted from columns if required to achieve this, with one character progressively
542
+ # deducted from the width of the widest column until the target is reached. When the
543
+ # table is printed, wrapping or truncation will then occur in these columns as required
544
+ # (depending on how they were configured).
545
+ #
546
+ # Note that regardless of the value passed to `max_table_width`, the table will always be left wide
547
+ # enough to accommodate at least 1 character's width of content for each column, and the padding
548
+ # configured for each column (by default 1 character either side), together with border characters
549
+ # (1 on each side of the table and 1 between adjacent columns). I.e. there is a certain width below width the
550
+ # Table will refuse to shrink itself.
551
+ #
552
+ # If `max_table_width` is passed the symbol `:screen`, then this method will behave as if it
553
+ # were passed an integer, with that integer being the width of the terminal.
554
+ #
555
+ # @param [Integer, :screen] the desired maximum table width
556
+ # @param [nil, Symbol, Integer, Array[Symbol|Integer]] except If passed one or multiple column labels,
557
+ # these columns will be excluded from resizing and will keep their current width.
558
+ # (Note if passing integers, these are not necessarily positional: only columns _explicitly_
559
+ # given an integer label will have these as labels.)
560
+ # @return [Table] the Table itself
561
+ def shrink_to(max_table_width, except: nil)
562
+ min_content_width_per_column = 1
563
+ min_total_column_content_width = num_columns * min_content_width_per_column
564
+ min_table_width = total_padding_width + total_borders_width + min_total_column_content_width
497
565
 
498
- if @title
499
- border_edge_width = (@border == :blank ? 0 : 2)
500
- columns = get_columns
501
- expand_to(
502
- Unicode::DisplayWidth.of(@title) +
503
- columns.first.left_padding +
504
- columns.last.right_padding +
505
- border_edge_width
506
- )
566
+ max_table_width = (max_table_width == :screen ? TTY::Screen.width : max_table_width)
567
+ max_table_width = Util.max(min_table_width, max_table_width)
568
+
569
+ required_reduction = Util.max(total_table_width - max_table_width, 0)
570
+
571
+ shrinkable_columns = get_columns(except: except)
572
+ required_reduction.times do
573
+ widest_column = shrinkable_columns.inject(shrinkable_columns.first) do |widest, column|
574
+ column.width >= widest.width ? column : widest
575
+ end
576
+
577
+ widest_column.width -= 1
507
578
  end
508
579
 
509
580
  self
@@ -609,8 +680,13 @@ module Tabulo
609
680
  private
610
681
 
611
682
  # @!visibility private
612
- def get_columns
613
- column_registry.values
683
+ def get_columns(except: nil)
684
+ if except
685
+ column_labels = except ? column_registry.keys - Array(except) : column_registry.keys
686
+ column_labels.map { |label| column_registry[label] }
687
+ else
688
+ column_registry.values
689
+ end
614
690
  end
615
691
 
616
692
  # @!visibility private
@@ -695,16 +771,35 @@ module Tabulo
695
771
  end
696
772
 
697
773
  # @!visibility private
698
- def expand_to(min_table_width)
699
- columns = get_columns
700
- num_columns = columns.count
701
- total_columns_padded_width = columns.inject(0) { |sum, column| sum + column.padded_width }
702
- total_borders = num_columns + 1
703
- unadjusted_table_width = total_columns_padded_width + total_borders
704
- required_increase = Util.max(min_table_width - unadjusted_table_width, 0)
774
+ # @return [Integer] the total combined width of padding characters
775
+ def total_padding_width
776
+ get_columns.inject(0) { |sum, column| sum + column.total_padding }
777
+ end
705
778
 
779
+ # @!visibility private
780
+ # @return [Integer] the total combined width of vertical border characters
781
+ def total_borders_width
782
+ num_columns + 1
783
+ end
784
+
785
+ # @!visibility private
786
+ # @return [Integer] the total combined width of column contents (excludes borders and padding)
787
+ def total_column_content_width
788
+ get_columns.inject(0) { |sum, column| sum + column.width }
789
+ end
790
+
791
+ # @!visibility private
792
+ # @return [Integer] the total actual width of the table as a whole
793
+ def total_table_width
794
+ total_column_content_width + total_padding_width + total_borders_width
795
+ end
796
+
797
+ # @!visibility private
798
+ def expand_to(min_table_width, except: nil)
799
+ required_increase = Util.max(min_table_width - total_table_width, 0)
800
+ expandable_columns = get_columns(except: except)
706
801
  required_increase.times do
707
- narrowest_column = columns.inject(columns.first) do |narrowest, column|
802
+ narrowest_column = expandable_columns.inject(expandable_columns.first) do |narrowest, column|
708
803
  column.width <= narrowest.width ? column : narrowest
709
804
  end
710
805
 
@@ -713,27 +808,8 @@ module Tabulo
713
808
  end
714
809
 
715
810
  # @!visibility private
716
- def shrink_to(max_table_width)
717
- columns = get_columns
718
- num_columns = columns.count
719
- total_columns_padded_width = columns.inject(0) { |sum, column| sum + column.padded_width }
720
- total_padding = columns.inject(0) { |sum, column| sum + column.total_padding }
721
- total_borders = num_columns + 1
722
- unadjusted_table_width = total_columns_padded_width + total_borders
723
-
724
- # Ensure max table width is at least wide enough to accommodate table borders and padding
725
- # and one character of content.
726
- min_table_width = total_padding + total_borders + column_registry.count
727
- max_table_width = Util.max(min_table_width, max_table_width)
728
- required_reduction = Util.max(unadjusted_table_width - max_table_width, 0)
729
-
730
- required_reduction.times do
731
- widest_column = columns.inject(columns.first) do |widest, column|
732
- column.width >= widest.width ? column : widest
733
- end
734
-
735
- widest_column.width -= 1
736
- end
811
+ def num_columns
812
+ column_registry.count
737
813
  end
738
814
 
739
815
  # @!visibility private
@@ -1,3 +1,3 @@
1
1
  module Tabulo
2
- VERSION = "2.7.3"
2
+ VERSION = "2.8.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tabulo
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.3
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Harvey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-19 00:00:00.000000000 Z
11
+ date: 2022-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-screen