about summary refs log tree commit diff stats
path: root/linux/tile/rpn.mu
Commit message (Collapse)AuthorAgeFilesLines
* 7867Kartik K. Agaram2021-03-071-44/+44
|
* 7842 - new directory organizationKartik K. Agaram2021-03-031-0/+911
Baremetal is now the default build target and therefore has its sources at the top-level. Baremetal programs build using the phase-2 Mu toolchain that requires a Linux kernel. This phase-2 codebase which used to be at the top-level is now under the linux/ directory. Finally, the phase-2 toolchain, while self-hosting, has a way to bootstrap from a C implementation, which is now stored in linux/bootstrap. The bootstrap C implementation uses some literate programming tools that are now in linux/bootstrap/tools. So the whole thing has gotten inverted. Each directory should build one artifact and include the main sources (along with standard library). Tools used for building it are relegated to sub-directories, even though those tools are often useful in their own right, and have had lots of interesting programs written using them. A couple of things have gotten dropped in this process: - I had old ways to run on just a Linux kernel, or with a Soso kernel. No more. - I had some old tooling for running a single test at the cursor. I haven't used that lately. Maybe I'll bring it back one day. The reorg isn't done yet. Still to do: - redo documentation everywhere. All the README files, all other markdown, particularly vocabulary.md. - clean up how-to-run comments at the start of programs everywhere - rethink what to do with the html/ directory. Do we even want to keep supporting it? In spite of these shortcomings, all the scripts at the top-level, linux/ and linux/bootstrap are working. The names of the scripts also feel reasonable. This is a good milestone to take stock at.
#n105'>105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
# This file is part of ranger, the console file manager.
# License: GNU GPL version 3, see the file "AUTHORS" for details.

"""This class provides convenient methods for movement operations.

Direction objects are handled just like dicts but provide
methods like up() and down() which give you the correct value
for the vertical direction, even if only the "up" or "down" key
has been defined.


>>> d = Direction(down=5)
>>> d.down()
5
>>> d.up()
-5
>>> bool(d.horizontal())
False
"""

from __future__ import (absolute_import, division, print_function)

import math


class Direction(dict):

    def __init__(self, dictionary=None, **keywords):
        if dictionary is not None:
            dict.__init__(self, dictionary)
        else:
            dict.__init__(self, keywords)
        if 'to' in self:
            self['down'] = self['to']
            self['absolute'] = True

    def copy(self):
        return Direction(**self)

    def _get_bool(self, first, second, fallback=None):
        try:
            return self[first]
        except KeyError:
            try:
                return not self[second]
            except KeyError:
                return fallback

    def _get_direction(self, first, second, fallback=0):
        try:
            return self[first]
        except KeyError:
            try:
                return -self[second]
            except KeyError:
                return fallback

    def up(self):  # pylint: disable=invalid-name
        return -Direction.down(self)  # pylint: disable=invalid-unary-operand-type

    def down(self):
        return Direction._get_direction(self, 'down', 'up')

    def right(self):
        return Direction._get_direction(self, 'right', 'left')

    def absolute(self):
        return Direction._get_bool(self, 'absolute', 'relative')

    def left(self):
        return -Direction.right(self)  # pylint: disable=invalid-unary-operand-type

    def relative(self):
        return not Direction.absolute(self)

    def vertical_direction(self):
        down = Direction.down(self)
        return (down > 0) - (down < 0)

    def horizontal_direction(self):
        right = Direction.right(self)
        return (right > 0) - (right < 0)

    def vertical(self):
        return set(self) & set(['up', 'down'])

    def horizontal(self):
        return set(self) & set(['left', 'right'])

    def pages(self):
        return 'pages' in self and self['pages']

    def percentage(self):
        return 'percentage' in self and self['percentage']

    def cycle(self):
        return self.get('cycle') in (True, 'true', 'on', 'yes')

    def one_indexed(self):
        return ('one_indexed' in self and
                self.get('one_indexed') in (True, 'true', 'on', 'yes'))

    def multiply(self, n):
        for key in ('up', 'right', 'down', 'left'):
            try:
                self[key] *= n
            except KeyError:
                pass

    def set(self, n):
        for key in ('up', 'right', 'down', 'left'):
            if key in self:
                self[key] = n

    def move(self, direction, override=None, minimum=0,  # pylint: disable=too-many-arguments
             maximum=9999, current=0, pagesize=1, offset=0):
        """Calculates the new position in a given boundary.

        Example:
        >>> d = Direction(pages=True)
        >>> d.move(direction=3)
        3
        >>> d.move(direction=3, current=2)
        5
        >>> d.move(direction=3, pagesize=5)
        15
        >>> # Note: we start to count at zero.
        >>> d.move(direction=3, pagesize=5, maximum=10)
        9
        >>> d.move(direction=9, override=2)
        18
        """
        pos = direction
        if override is not None:
            if self.absolute():
                if self.one_indexed():
                    pos = override - 1
                else:
                    pos = override
            else:
                pos *= override
        if self.pages():
            pos *= pagesize
        elif self.percentage():
            pos *= maximum / 100
        if self.absolute():
            if pos < minimum:
                pos += maximum
        else:
            pos += current
        if self.cycle():
            cycles, pos = divmod(pos, (maximum + offset - minimum))
            self['_move_cycles'] = int(cycles)
            ret = minimum + pos
        else:
            ret = max(min(pos, maximum + offset - 1), minimum)
        # Round towards the direction we're moving from.
        # From the UI point of view, round down. See: #912.
        if direction < 0:
            ret = int(math.ceil(ret))
        else:
            ret = int(ret)
        return ret

    def move_cycles(self):
        return self.get('_move_cycles', 0)

    def select(self, lst, current, pagesize, override=None, offset=1):
        dest = self.move(direction=self.down(), override=override,
                         current=current, pagesize=pagesize, minimum=0, maximum=len(lst) + 1)
        selection = lst[min(current, dest):max(current, dest) + offset]
        return dest + offset - 1, selection


if __name__ == '__main__':
    import doctest
    doctest.testmod()